Repository: grzegorzmazur/yacas Branch: master Commit: 7df0c6751901 Files: 602 Total size: 10.5 MB Directory structure: gitextract_ep2z9l5r/ ├── .clang-format ├── .gitignore ├── .vscode/ │ ├── launch.json │ └── settings.json ├── AUTHORS ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── COPYING ├── ChangeLog ├── README.rst ├── TODO ├── appveyor.yml ├── build.xml ├── cyacas/ │ ├── CMakeLists.txt │ ├── libyacas/ │ │ ├── CMakeLists.txt │ │ ├── config/ │ │ │ └── yacas/ │ │ │ └── yacas_version.h.in │ │ ├── include/ │ │ │ └── yacas/ │ │ │ ├── GPL_stuff.h │ │ │ ├── anumber.h │ │ │ ├── anumber.inl │ │ │ ├── arggetter.h │ │ │ ├── arrayclass.h │ │ │ ├── associationclass.h │ │ │ ├── corefunctions.h │ │ │ ├── deffile.h │ │ │ ├── errors.h │ │ │ ├── evalfunc.h │ │ │ ├── genericobject.h │ │ │ ├── infixparser.h │ │ │ ├── lispatom.h │ │ │ ├── lispenvironment.h │ │ │ ├── lisperror.h │ │ │ ├── lispeval.h │ │ │ ├── lispevalhash.h │ │ │ ├── lispglobals.h │ │ │ ├── lisphash.h │ │ │ ├── lispio.h │ │ │ ├── lispobject.h │ │ │ ├── lispoperator.h │ │ │ ├── lispparser.h │ │ │ ├── lispstring.h │ │ │ ├── lispuserfunc.h │ │ │ ├── mathcommands.h │ │ │ ├── mathuserfunc.h │ │ │ ├── mempool.h │ │ │ ├── noncopyable.h │ │ │ ├── numbers.h │ │ │ ├── patcher.h │ │ │ ├── patternclass.h │ │ │ ├── patterns.h │ │ │ ├── platfileio.h │ │ │ ├── platmath.h │ │ │ ├── refcount.h │ │ │ ├── standard.h │ │ │ ├── standard.inl │ │ │ ├── string_utils.h │ │ │ ├── stringio.h │ │ │ ├── substitute.h │ │ │ ├── tokenizer.h │ │ │ ├── utf8/ │ │ │ │ ├── checked.h │ │ │ │ ├── core.h │ │ │ │ ├── cpp11.h │ │ │ │ ├── cpp17.h │ │ │ │ ├── cpp20.h │ │ │ │ └── unchecked.h │ │ │ ├── utf8.h │ │ │ ├── xmltokenizer.h │ │ │ └── yacas.h │ │ └── src/ │ │ ├── anumber.cpp │ │ ├── arggetter.cpp │ │ ├── associationclass.cpp │ │ ├── deffile.cpp │ │ ├── errors.cpp │ │ ├── infixparser.cpp │ │ ├── lispatom.cpp │ │ ├── lispenvironment.cpp │ │ ├── lisperror.cpp │ │ ├── lispeval.cpp │ │ ├── lispevalhash.cpp │ │ ├── lisphash.cpp │ │ ├── lispio.cpp │ │ ├── lispobject.cpp │ │ ├── lispparser.cpp │ │ ├── lispuserfunc.cpp │ │ ├── mathcommands.cpp │ │ ├── mathcommands2.cpp │ │ ├── mathcommands3.cpp │ │ ├── mathuserfunc.cpp │ │ ├── mempool.cpp │ │ ├── numbers.cpp │ │ ├── patcher.cpp │ │ ├── patternclass.cpp │ │ ├── patterns.cpp │ │ ├── platmath.cpp │ │ ├── standard.cpp │ │ ├── stdfileio.cpp │ │ ├── stringio.cpp │ │ ├── substitute.cpp │ │ ├── tokenizer.cpp │ │ ├── xmltokenizer.cpp │ │ ├── yacasapi.cpp │ │ └── yacasnumbers.cpp │ ├── libyacas_mp/ │ │ ├── CMakeLists.txt │ │ ├── benchmark/ │ │ │ ├── CMakeLists.txt │ │ │ └── src/ │ │ │ └── nn_benchmark.cpp │ │ ├── include/ │ │ │ └── yacas/ │ │ │ └── mp/ │ │ │ ├── limbs_vector.hpp │ │ │ ├── nn.hpp │ │ │ ├── rr.hpp │ │ │ └── zz.hpp │ │ ├── src/ │ │ │ ├── limbs_vector.cpp │ │ │ ├── nn.cpp │ │ │ ├── rr.cpp │ │ │ └── zz.cpp │ │ └── test/ │ │ ├── CMakeLists.txt │ │ └── src/ │ │ ├── nn_test.cpp │ │ └── zz_test.cpp │ ├── packaging/ │ │ ├── deb/ │ │ │ ├── changelog │ │ │ ├── compat │ │ │ ├── control │ │ │ ├── copyright │ │ │ ├── missing-sources/ │ │ │ │ ├── jquery-ui.js │ │ │ │ ├── jquery.autosize.js │ │ │ │ ├── jquery.js │ │ │ │ ├── jquery.ui-contextmenu.js │ │ │ │ └── plotly-1.49.0.js │ │ │ ├── rules │ │ │ ├── source/ │ │ │ │ ├── format │ │ │ │ └── include-binaries │ │ │ └── yacas.1 │ │ ├── ebuild/ │ │ │ └── yacas.ebuild │ │ ├── flatpak/ │ │ │ ├── org.yacas.yacas-gui.appdata.xml │ │ │ ├── org.yacas.yacas-gui.json │ │ │ └── org.yacas.yacas.json │ │ ├── nsis/ │ │ │ ├── COPYING │ │ │ └── yacas-win64.nsi │ │ ├── pkg/ │ │ │ ├── distribution.xml │ │ │ ├── license.txt │ │ │ └── readme.html │ │ ├── rpm/ │ │ │ └── yacas.spec │ │ └── snap/ │ │ ├── snap/ │ │ │ └── gui/ │ │ │ └── yacas.gui.desktop │ │ └── snapcraft.yaml │ ├── xeus-yacas/ │ │ ├── CMakeLists.txt │ │ ├── include/ │ │ │ └── xeus-yacas/ │ │ │ └── xeus-yacas.hpp │ │ └── src/ │ │ ├── interpreter.cpp │ │ └── main.cpp │ ├── yacas/ │ │ ├── CMakeLists.txt │ │ ├── include/ │ │ │ ├── commandline.h │ │ │ ├── core_yacasmain.h │ │ │ ├── stdcommandline.h │ │ │ ├── unixcommandline.h │ │ │ └── win32commandline.h │ │ ├── res/ │ │ │ └── yacas.rc │ │ └── src/ │ │ ├── commandline.cpp │ │ ├── js_interface.cpp │ │ ├── stdcommandline.cpp │ │ ├── unixcommandline.cpp │ │ ├── win32commandline.cpp │ │ └── yacasmain.cpp │ ├── yacas-gui/ │ │ ├── CMakeLists.txt │ │ ├── img.qrc │ │ ├── include/ │ │ │ ├── cellproxy.h │ │ │ ├── mainwindow.h │ │ │ ├── preferences.h │ │ │ ├── preferences_dialog.h │ │ │ ├── yacasengine.h │ │ │ ├── yacasrequest.h │ │ │ └── yacasserver.h │ │ ├── resources/ │ │ │ ├── CMakeLists.txt │ │ │ ├── jquery/ │ │ │ │ ├── jquery.jeditable.autogrow.js │ │ │ │ └── jquery.jeditable.js │ │ │ ├── mathbar/ │ │ │ │ ├── functions.json │ │ │ │ ├── functions_parser.js │ │ │ │ ├── mathBar.js │ │ │ │ └── mathbar.css │ │ │ ├── webchannel/ │ │ │ │ └── qwebchannel.js │ │ │ ├── yacas-online.html │ │ │ ├── yacas_gui/ │ │ │ │ ├── attic/ │ │ │ │ │ └── intput.editable.js │ │ │ │ ├── yacas_gui.css │ │ │ │ └── yacas_gui.js │ │ │ └── yacas_gui.html │ │ ├── src/ │ │ │ ├── cellproxy.cpp │ │ │ ├── main.cpp │ │ │ ├── mainwindow.cpp │ │ │ ├── preferences.cpp │ │ │ ├── preferences_dialog.cpp │ │ │ ├── yacasengine.cpp │ │ │ ├── yacasrequest.cpp │ │ │ └── yacasserver.cpp │ │ ├── ui/ │ │ │ ├── mainwindow.ui │ │ │ └── preferences_dialog.ui │ │ ├── winres/ │ │ │ └── yacas_gui.rc │ │ ├── yacas-gui.desktop │ │ └── yacas.icns │ └── yacas-kernel/ │ ├── CMakeLists.txt │ ├── include/ │ │ ├── base64.hpp │ │ ├── hmac_sha256.hpp │ │ ├── yacas_engine.hpp │ │ └── yacas_kernel.hpp │ └── src/ │ ├── base64.cpp │ ├── hmac_sha256.cpp │ ├── main.cpp │ ├── yacas_engine.cpp │ └── yacas_kernel.cpp ├── docs/ │ ├── CMakeLists.txt │ ├── Makefile │ ├── book_of_algorithms/ │ │ ├── basic.rst │ │ ├── index.rst │ │ ├── integration.rst │ │ ├── multivar.rst │ │ ├── numtheory.rst │ │ ├── references.bib │ │ ├── references.rst │ │ ├── sturm-sequences.rst │ │ └── transforms.rst │ ├── conf.py │ ├── credits.rst │ ├── getting_started/ │ │ └── index.rst │ ├── glossary.rst │ ├── index.rst │ ├── license.rst │ ├── make.bat │ ├── programming_in_yacas/ │ │ └── index.rst │ ├── reference_manual/ │ │ ├── arithmetic.rst │ │ ├── calc.rst │ │ ├── consts.rst │ │ ├── controlflow.rst │ │ ├── debugging.rst │ │ ├── elementary.rst │ │ ├── functional.rst │ │ ├── graphs.rst │ │ ├── index.rst │ │ ├── io.rst │ │ ├── linear-algebra.rst │ │ ├── lists.rst │ │ ├── logic.rst │ │ ├── misc.rst │ │ ├── number-theory.rst │ │ ├── numerical-methods.rst │ │ ├── ode.rst │ │ ├── physics.rst │ │ ├── plot.rst │ │ ├── predicates.rst │ │ ├── probability-and-statistics.rst │ │ ├── programming.rst │ │ ├── random.rst │ │ ├── simplify.rst │ │ ├── solvers.rst │ │ ├── special.rst │ │ ├── strings.rst │ │ ├── univariate-polynomials.rst │ │ └── vars.rst │ ├── requirements.txt │ ├── tutorial/ │ │ └── index.rst │ └── util/ │ └── yacasdomain.py ├── jyacas/ │ ├── CMakeLists.txt │ ├── CVersion.java.in │ ├── JavaYacas.1 │ ├── MANIFEST.MF │ ├── lib/ │ │ ├── hamcrest-core-1.3.jar │ │ └── junit-4.11.jar │ └── net/ │ └── sf/ │ └── yacas/ │ ├── ArrayClass.java │ ├── AssociationClass.java │ ├── BackQuoteBehaviour.java │ ├── BasicEvaluator.java │ ├── BigNumber.java │ ├── BranchingUserFunction.java │ ├── CYacas.java │ ├── CachedStdFileInput.java │ ├── EvalFuncBase.java │ ├── GenericClass.java │ ├── InfixParser.java │ ├── InfixPrinter.java │ ├── InputDirectories.java │ ├── InputStatus.java │ ├── JarInputFile.java │ ├── LispArgList.java │ ├── LispArityUserFunction.java │ ├── LispAtom.java │ ├── LispDefFile.java │ ├── LispDefFiles.java │ ├── LispEnvironment.java │ ├── LispError.java │ ├── LispEvaluatorBase.java │ ├── LispGenericClass.java │ ├── LispGlobalVariable.java │ ├── LispHashTable.java │ ├── LispInFixOperator.java │ ├── LispInput.java │ ├── LispIterator.java │ ├── LispLocalFrame.java │ ├── LispMultiUserFunction.java │ ├── LispNumber.java │ ├── LispObject.java │ ├── LispOperators.java │ ├── LispParser.java │ ├── LispPrinter.java │ ├── LispPtr.java │ ├── LispPtrArray.java │ ├── LispStandard.java │ ├── LispSubList.java │ ├── LispTokenizer.java │ ├── LispUserFunction.java │ ├── ListedBranchingUserFunction.java │ ├── ListedMacroUserFunction.java │ ├── LocalSymbolBehaviour.java │ ├── MacroUserFunction.java │ ├── MatchAtom.java │ ├── MatchNumber.java │ ├── MatchSubList.java │ ├── MatchVariable.java │ ├── MathCommands.java │ ├── ParsedObject.java │ ├── PatternClass.java │ ├── StdFileInput.java │ ├── StreamGobbler.java │ ├── StringInput.java │ ├── SubstBehaviour.java │ ├── SubstBehaviourBase.java │ ├── UserStackInformation.java │ ├── XmlTokenizer.java │ ├── YacasConsole.java │ ├── YacasEvalCaller.java │ ├── YacasEvaluator.java │ ├── YacasException.java │ ├── YacasInterpreter.java │ ├── YacasParamMatcherBase.java │ ├── YacasPatternPredicateBase.java │ └── YacasTest.java ├── man/ │ ├── CMakeLists.txt │ └── yacas.1.rst ├── papers/ │ ├── llncs.cls │ ├── paper1.tex │ └── paper2.tex ├── scripts/ │ ├── array.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── assoc.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── base.rep/ │ │ ├── math.ys │ │ └── math.ys.def │ ├── c_form.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── calendar.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── complex.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ └── om.ys │ ├── constants.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ └── om.ys │ ├── controlflow.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── cse.rep/ │ │ ├── cse.ys │ │ └── cse.ys.def │ ├── debug.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── deffunc.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── deriv.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── example.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── examples/ │ │ ├── ABIN.ys │ │ ├── MinimumSpanningTree.ys │ │ ├── benchbuild.ys │ │ ├── benchmark.ys │ │ ├── benchmark2.ys │ │ ├── findsum.ys │ │ ├── goldbach.ys │ │ ├── pi.ys │ │ ├── queens.ys │ │ ├── series.ys │ │ └── wordproblems.ys │ ├── factors.rep/ │ │ ├── binaryfactors.ys │ │ ├── binaryfactors.ys.def │ │ ├── code.ys │ │ └── code.ys.def │ ├── functional.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ └── om.ys │ ├── graph.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── html.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── integrate.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ └── om.ys │ ├── io.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── defaultprint.ys │ │ ├── defaultprint.ys.def │ │ ├── errors.ys │ │ ├── formula.ys │ │ └── print.ys │ ├── limit.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ └── om.ys │ ├── linalg.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── lists.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── scopestack.ys │ │ └── scopestack.ys.def │ ├── localrules.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── logic.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ └── om.ys │ ├── multivar.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── makemulti.ys │ │ ├── sparsenomial.ys │ │ ├── sparsetree.ys │ │ └── sparsetree.ys.def │ ├── newly.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── nintegrate.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── numbers.rep/ │ │ ├── GaussianIntegers.ys │ │ ├── GaussianIntegers.ys.def │ │ ├── NumberTheory.ys │ │ ├── NumberTheory.ys.def │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── nthroot.ys │ │ ├── nthroot.ys.def │ │ └── om.ys │ ├── odesolver.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── openmath.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── orthopoly.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── packages.ys │ ├── padic.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── patterns.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── physics.rep/ │ │ └── quantum/ │ │ ├── clebsch-gordan.ys │ │ └── clebsch-gordan.ys.def │ ├── plots.rep/ │ │ ├── backends-2d.ys │ │ ├── backends-3d.ys │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── plot2d.ys │ │ ├── plot2d.ys.def │ │ ├── plot3d.ys │ │ └── plot3d.ys.def │ ├── predicates.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── probability.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── products.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── pslq.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── r_form.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── rabinmiller.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── radsimp.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── random.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── rational.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── simplify.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── factorial.ys │ │ └── factorial.ys.def │ ├── solve.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ └── om.ys │ ├── specfunc.rep/ │ │ ├── bernou.ys │ │ ├── bernou.ys.def │ │ ├── bessel.ys │ │ ├── bessel.ys.def │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── gamma.ys │ │ ├── gamma.ys.def │ │ ├── gammaconst.ys │ │ ├── gammaconst.ys.def │ │ ├── om.ys │ │ ├── zeta.ys │ │ └── zeta.ys.def │ ├── standard.ys │ ├── standard.ys.def │ ├── statistics.rep/ │ │ ├── distributions.ys │ │ ├── distributions.ys.def │ │ ├── hypothesystest.ys │ │ ├── hypothesystest.ys.def │ │ ├── incompletegamma.ys │ │ ├── incompletegamma.ys.def │ │ ├── randomtest.ys │ │ ├── regression.ys │ │ ├── regression.ys.def │ │ ├── statistics.ys │ │ └── statistics.ys.def │ ├── stats.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── stdarith.ys │ ├── stdarith.ys.def │ ├── stdfuncs.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── elemfuncs.ys │ │ ├── elemfuncs.ys.def │ │ ├── numerical.ys │ │ ├── numerical.ys.def │ │ ├── nummethods.ys │ │ ├── nummethods.ys.def │ │ └── om.ys │ ├── stdopers.ys │ ├── stubs.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ └── om.ys │ ├── substitute.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── sums.rep/ │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── om.ys │ │ ├── taylor.ys │ │ ├── taylor.ys.def │ │ ├── taylor3.ys │ │ └── taylor3.ys.def │ ├── tensor.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── testers.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── texform.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── transforms.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── trigsimp.rep/ │ │ ├── code.ys │ │ └── code.ys.def │ ├── univar.rep/ │ │ ├── Cyclotomic.ys │ │ ├── Cyclotomic.ys.def │ │ ├── code.ys │ │ ├── code.ys.def │ │ ├── sparse.ys │ │ ├── sparse.ys.def │ │ ├── sturm.ys │ │ └── sturm.ys.def │ └── yacasinit.ys ├── tests/ │ ├── CMakeLists.txt │ ├── GaussianIntegers.yts │ ├── arithmetic.yts │ ├── association.yts │ ├── binaryfactors.yts │ ├── bitops.yts │ ├── c_tex_form.yts │ ├── calculus.yts │ ├── calendar.yts │ ├── canprove.yts │ ├── comments.yts │ ├── complex.yts │ ├── cyclotomic.yts │ ├── deriv.yts │ ├── dimensions.yts │ ├── dot.yts │ ├── graphs.yts │ ├── includetestfiles │ ├── integrate.yts │ ├── io.yts │ ├── journal.yts │ ├── linalg.yts │ ├── lists.yts │ ├── logic_simplify_test.yts │ ├── macro.yts │ ├── matrixpower.yts │ ├── multivar.yts │ ├── newly.yts │ ├── nthroot.yts │ ├── numbers.yts │ ├── numerics.yts │ ├── nummethods.yts │ ├── ode.yts │ ├── openmath.yts │ ├── orthopoly.yts │ ├── outer.yts │ ├── padic.yts │ ├── physics.yts │ ├── plots.yts │ ├── poly.yts │ ├── predicates.yts │ ├── products.yts │ ├── programming.yts │ ├── radsimp.yts │ ├── rational.yts │ ├── regress.yts │ ├── scopestack.yts │ ├── simplify.yts │ ├── solve.yts │ ├── sturm.yts │ ├── sums.yts │ ├── tensors.yts │ ├── test-yacas │ ├── test-yacas.bat │ ├── tr.yts │ ├── trace.yts │ └── transforms.yts ├── third_party/ │ └── README.rst ├── utils/ │ └── pre-commit └── yacas_UNINSTALL.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ --- Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Right AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: false BinPackParameters: false BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: true AfterNamespace: false AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: AfterColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 80 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: false ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve IncludeCategories: - Regex: '^"(llvm|llvm-c|clang|clang-c)/' Priority: 2 - Regex: '^(<|"(gtest|gmock|isl|json)/)' Priority: 3 - Regex: '.*' Priority: 1 IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false IndentPPDirectives: AfterHash IndentWidth: 4 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: true MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: All ObjCBlockIndentWidth: 4 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Left RawStringFormats: - Delimiters: [pb] Language: TextProto BasedOnStyle: google ReflowComments: true SortIncludes: true SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp11 TabWidth: 8 UseTab: Never ... ================================================ FILE: .gitignore ================================================ /nbproject/ /build/ /install/ *.cmake /CMakeFiles/ /CMakeScripts/ CMakeCache.txt /Release/ /Debug/ /Yacas.build/ /Yacas.xcodeproj/ /JavaYacas/CVersion.java /TEST-net.sf.yacas.YacasTest.xml /yacas-logfile.txt /jyacas/net/sf/yacas/CVersion.java .DS_Store .vscode/ipch/* *.pyc .vs/ out/ ================================================ FILE: .vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { "name": "(gdb) Launch yacas", "type": "cppdbg", "request": "launch", "program": "${workspaceRoot}/build/cyacas/yacas/yacas", "args": ["--rootdir", "${workspaceRoot}/scripts/"], "stopAtEntry": false, "cwd": "${workspaceRoot}", "environment": [], "externalConsole": true, "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] }, { "name": "(gdb) Launch yacas arithmetic.yts", "type": "cppdbg", "request": "launch", "program": "${workspaceRoot}/build/cyacas/yacas/yacas", "args": ["--rootdir", "${workspaceRoot}/scripts/", "${workspaceRoot}/tests/arithmetic.yts"], "stopAtEntry": false, "cwd": "${workspaceRoot}", "environment": [], "externalConsole": true, "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] }, { "name": "(gdb) Launch yacas numerics.yts", "type": "cppdbg", "request": "launch", "program": "${workspaceRoot}/build/cyacas/yacas/yacas", "args": ["--rootdir", "${workspaceRoot}/scripts/", "${workspaceRoot}/tests/numerics.yts"], "stopAtEntry": false, "cwd": "${workspaceRoot}", "environment": [], "externalConsole": true, "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] }, { "name": "(gdb) Launch yacas orthopoly.yts", "type": "cppdbg", "request": "launch", "program": "${workspaceRoot}/build/cyacas/yacas/yacas", "args": ["--rootdir", "${workspaceRoot}/scripts/", "${workspaceRoot}/tests/orthoppoly.yts"], "stopAtEntry": false, "cwd": "${workspaceRoot}", "environment": [], "externalConsole": true, "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ] } ], "compounds": [] } ================================================ FILE: .vscode/settings.json ================================================ { "C_Cpp.intelliSenseEngine": "Default", "editor.insertSpaces": true, "editor.tabSize": 4, "editor.detectIndentation": true, "files.associations": { "*.ltx": "latex", "cctype": "cpp", "cmath": "cpp", "csignal": "cpp", "cstdarg": "cpp", "cstddef": "cpp", "cstdio": "cpp", "cstdlib": "cpp", "cstring": "cpp", "ctime": "cpp", "cwchar": "cpp", "cwctype": "cpp", "array": "cpp", "atomic": "cpp", "*.tcc": "cpp", "chrono": "cpp", "condition_variable": "cpp", "cstdint": "cpp", "exception": "cpp", "functional": "cpp", "future": "cpp", "initializer_list": "cpp", "iosfwd": "cpp", "limits": "cpp", "mutex": "cpp", "new": "cpp", "ratio": "cpp", "stdexcept": "cpp", "system_error": "cpp", "thread": "cpp", "tuple": "cpp", "type_traits": "cpp", "typeinfo": "cpp", "utility": "cpp", "codecvt": "cpp", "bitset": "cpp", "clocale": "cpp", "fstream": "cpp", "iomanip": "cpp", "iostream": "cpp", "istream": "cpp", "memory": "cpp", "ostream": "cpp", "sstream": "cpp", "streambuf": "cpp", "algorithm": "cpp", "*.ipp": "cpp", "deque": "cpp", "string": "cpp", "unordered_map": "cpp", "unordered_set": "cpp", "vector": "cpp", "numeric": "cpp", "optional": "cpp", "string_view": "cpp", "variant": "cpp" }, "python.pythonPath": "/usr/bin/python3", "files.exclude": { "**/.DS_Store": true, "**/.git": true, "**/.hg": true, "**/.svn": true, "**/*.pyc": true, "**/build": true, "**/CVS": true }, "files.trimTrailingWhitespace": true, "restructuredtext.builtDocumentationPath": "${workspaceRoot}/build/docs/html", "cmake.configureOnOpen": true, "workbench.colorCustomizations": { "statusBar.background": "#E49427", "statusBar.debuggingBackground": "#E49427", "statusBar.noFolderBackground": "#E49427", "statussBar.prominentBackground": "#E49427" }, "files.watcherExclude": { "**/build/**": true }, "cmake.installPrefix": "${workspaceRoot}/build/install/${buildKit}/${buildType}", "cmake.configureSettings": { "Qt5Core_DIR": "/usr/lib/x86_64-linux-gnu/cmake/Qt5Core", "Qt5Widgets_DIR": "/usr/lib/x86_64-linux-gnu/cmake/Qt5Widgets", "Qt5WebEngine_DIR": "/usr/lib/x86_64-linux-gnu/cmake/Qt5WebEngine", "Qt5WebEngineWidgets_DIR": "/usr/lib/x86_64-linux-gnu/cmake/Qt5WebEngineWidgets", "Qt5Svg_DIR": "/usr/lib/x86_64-linux-gnu/cmake/Qt5Svg" }, "python.linting.pylintEnabled": true, "python.linting.enabled": true, "restructuredtext.confPath": "" } ================================================ FILE: AUTHORS ================================================ ************ Credits [*]_ ************ Original/primary authors ======================== Ayal Pinkus *apinkus "AT" xs4all "DOT" nl* This project was started by Ayal Pinkus who remains the main author and the primary maintainer. Serge Winitzki *serge "AT" cosmos "DOT" phy "DOT" tufts "DOT" edu* Added factorials over rationals, TeXForm, did a major overhaul of the introduction manual (actually, he wrote large part of the manual as it is), and initiated numerous improvements and test code for Yacas, and implemented yacas_client. Actually, Serge has been one of the larger contributors, and the main force behind the improved documentation. Jitse Niesen *jn221 "AT" damtp "DOT" cam "DOT" ac "DOT" uk* Reported some bugs, helped improve various parts of Yacas, and greatly improved the manual for Yacas. Maintainer ========== Grzegorz Mazur *teoretyk "AT" gmail "DOT" com* Contributors ============ Jim Apple *japple "AT" freeshell "DOT" org* Reported bugs and supplied improved code for gcc 3.3.4 Mark Arrasmith *arrasmith "AT" math "DOT" twsu "DOT" edu* Helped greatly in setting up the fltk-based graphicaluser interface, and fixed some bugs relating to limits regarding infinity. Fred Bacon *bacon "AT" aerodyne "DOT" com* Fixed some compiler errors on the newer gcc compiles. Reported some important bugs. Jay Belanger *belanger "AT" truman "DOT" edu* Reported some bugs and improved some of the GnuPlot code. He also wrote the yacas.el file, which allows you to run yacas from within emacs. Roberto Colistete Junior Is maintaining a version of `Yacas for SymbianOS `_. Sebastian Ferraro *sferraro "AT" criba "DOT" edu "DOT" ar* Reported bugs and supplied improved code (determinants). John Fremlin Added some code for fast calculation of roots of a cubic polynomial. Peter Gilbert *peterdgilbert "AT" gmail "DOT" com* Made many improvements to the C++ code to make it conform more to standard C++ coding conventions (class interfaces looking more like stl), improved the regression test suite. James Gilbertson *azurite "AT" telusplanet "DOT" net* Win32 port, improved error reporting. Added initial version of Karatsuba multiplication, and added some matrix functions to the math library. Gabor Grothendieck Gabor is the maintainer of `Ryacas `_, and gave valuable feedback on the new web site. Rene Grothmann *2004 "AT" rene-grothmann "DOT" de* Married Euler to Yacas. Franz Hack *franz.hack "AT" web "DOT" de* Supplied a Delphi interface to the Yacas DLL. Ingrid Halters Helped improve the ease of use of the Yacas web site. Mark Hatsell *mark "AT" autograph-maths "DOT" com* Made the server code work on Windows. Joris van der Hoeven *TeXmacs "AT" math "DOT" u-psud "DOT" fr* Helped with texmacs support. Wolfgang Hšnig *pocket_software "AT" web "DOT" de* Created a port of Yacas that runs on PocketPC, to be found `here `_. Daniel Richard G. *straker "AT" MIT "DOT" EDU* Added autoconf/automake scripts, made Sun/Sgi compilation possible, created a rpm spec file, many many many changes to clean up the source distribution. Igor Khavkine Added 'Diverge' and 'Curl', and implemented threading for the derivative operator (the gradient). Fixed GMP code. John Lapeyre Made some modifications to the make file, and improved some math code. Jonathan Leto *jonathan "AT" leto "DOT" net* Helped improve the integration algorithm, and helped extend the tests used for Yacas (finding numerous bugs). Vladimir Livshits *livshits "AT" cs "DOT" stanford "DOT" edu* Set up the initial sourceforge CVS repository, and updated the Windows version source code. He also greatly improved the logic theorem prover code. Eugenia Loli Helped build the BeOS version of Yacas. Adolf Mathias *adolf_mathias "AT" web "DOT" de* Grzegorz Mazur *teoretyk "AT" gmail "DOT" com* Pablo De Nápoli *pdenapo "AT" yahoo "DOT" com* Fixed the configure script so Yacas compiles under cygwin. Gopal Narayanan *gopal "AT" debian "DOT" org* Debian package maintainer. Made a man page for Yacas. Marta Noga *marta.noga "AT" gmail "DOT" com* Christian Obrecht *christian "DOT" obrecht "AT" wanadoo "DOT" fr* Made a much better Limit, and made Yacas behave better at infinity. Alberto González Palomo Implemented a console-mode version of Yacas for AgendaVR. Changed the directory structure for the script files, and implemented initial support for OpenMath. Doreen Pinkus *d "DOT" pinkus "AT" hccnet "DOT" nl* Designed the second version of the Web site for Yacas. Mike Pinna *mike "AT" autograph-maths "DOT" com* Applied some bug fixes. Savario Prinz *yacas "AT" mac "DOT" com* Built a fantastic Mac version of Yacas. Dirk Reusch Added some linear algebra functions, and fixed some predicate functions. Daniel Rigby Brought a client-server structure to the EPOC32 version of Yacas. Juan Pablo Romero *jpablo_romero "AT" hotmail "DOT" com* Reported many bugs, made many suggestions for improvements, and supplied improved code (yacas scripts and makefile code). Robert V Schipper *rvs "AT" achilles "DOT" nfia "DOT" org* Ironed out a few bugs in Yacas. Schneelocke Reported an important bug in numeric calculations. HenSiong Tan *tan "AT" stat "DOT" psu "DOT" edu* Yannick Versley *yannick "AT" versley "DOT" de* Sent some patches regarding bugs relating integration and differentiation. Adrian V. *qwert2003 "AT" users "DOT" sourceforge "DOT" net* Yijun Yu *y.yu "AT" open "DOT" ac "DOT" uk* Implemented LDU decomposition Ladislav Zejda Supplied patches to make Yacas work on Dec Alpha's. Andrei Zorine Started the body of statistics code. .. [*] All with last-known email addresses mangled in an obvious way ================================================ FILE: CMakeLists.txt ================================================ cmake_minimum_required (VERSION 3.10) foreach (p CMP0048 CMP0054 CMP0071 CMP0135) if (POLICY ${p}) cmake_policy(SET ${p} NEW) endif () endforeach () option (ENABLE_CYACAS_CONSOLE "build the C++ yacas text console" ON) option (ENABLE_CYACAS_GUI "build the C++ yacas GUI application" ON) option (ENABLE_CYACAS_GUI_PRIVATE_CODEMIRROR "use private copy of CodeMirror in yacas GUI application" ON) option (ENABLE_CYACAS_GUI_PRIVATE_MATHJAX "use private copy of MathJAX in yacas GUI application" ON) option (ENABLE_CYACAS_KERNEL "build the C++ yacas Jupyter kernel" OFF) option (ENABLE_CYACAS_XEUS "build the C++ yacas Xeus kernel" OFF) option (ENABLE_CYACAS_UNIT_TESTS "build the C++ yacas engine unit tests" OFF) option (ENABLE_CYACAS_BENCHMARKS "build the C++ yacas engine benchmarks" OFF) option (ENABLE_JYACAS "build the Java yacas engine" OFF) option (ENABLE_DOCS "generate documentation" OFF) option (ENABLE_CODE_COVERAGE "enable coverage reporting" OFF) if (ENABLE_CYACAS_CONSOLE OR ENABLE_CYACAS_GUI OR ENABLE_CYACAS_KERNEL) set (ENABLE_CYACAS ON) else () set (ENABLE_CYACAS OFF) endif() set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") set (LANGUAGES CXX C) if (ENABLE_JYACAS) find_package (Java) include (UseJava) set (LANGUAGES ${LANGUAGES} Java) endif () project (yacas VERSION 1.9.2 LANGUAGES ${LANGUAGES}) set (CMAKE_CXX_STANDARD 23) set (CMAKE_CXX_STANDARD_REQUIRED ON) set (CMAKE_CXX_EXTENSIONS OFF) include (GNUInstallDirs) include (CTest) set (YACAS_SCRIPTS scripts/array.rep/code.ys scripts/array.rep/code.ys.def scripts/assoc.rep/code.ys scripts/assoc.rep/code.ys.def scripts/base.rep/math.ys scripts/base.rep/math.ys.def scripts/c_form.rep/code.ys scripts/c_form.rep/code.ys.def scripts/calendar.rep/code.ys scripts/calendar.rep/code.ys.def scripts/complex.rep/code.ys scripts/complex.rep/code.ys.def scripts/complex.rep/om.ys scripts/constants.rep/code.ys scripts/constants.rep/code.ys.def scripts/constants.rep/om.ys scripts/controlflow.rep/code.ys scripts/controlflow.rep/code.ys.def scripts/cse.rep/cse.ys scripts/cse.rep/cse.ys.def scripts/debug.rep/code.ys scripts/debug.rep/code.ys.def scripts/deffunc.rep/code.ys scripts/deffunc.rep/code.ys.def scripts/deriv.rep/code.ys scripts/deriv.rep/code.ys.def scripts/example.rep/code.ys scripts/example.rep/code.ys.def scripts/factors.rep/binaryfactors.ys scripts/factors.rep/binaryfactors.ys.def scripts/factors.rep/code.ys scripts/factors.rep/code.ys.def scripts/functional.rep/code.ys scripts/functional.rep/code.ys.def scripts/functional.rep/om.ys scripts/graph.rep/code.ys scripts/graph.rep/code.ys.def scripts/html.rep/code.ys scripts/html.rep/code.ys.def scripts/integrate.rep/code.ys scripts/integrate.rep/code.ys.def scripts/integrate.rep/om.ys scripts/io.rep/code.ys scripts/io.rep/code.ys.def scripts/io.rep/defaultprint.ys scripts/io.rep/defaultprint.ys.def scripts/io.rep/errors.ys scripts/io.rep/formula.ys scripts/io.rep/print.ys scripts/limit.rep/code.ys scripts/limit.rep/code.ys.def scripts/limit.rep/om.ys scripts/linalg.rep/code.ys scripts/linalg.rep/code.ys.def scripts/lists.rep/code.ys scripts/lists.rep/code.ys.def scripts/lists.rep/scopestack.ys scripts/lists.rep/scopestack.ys.def scripts/localrules.rep/code.ys scripts/localrules.rep/code.ys.def scripts/logic.rep/code.ys scripts/logic.rep/code.ys.def scripts/logic.rep/om.ys scripts/multivar.rep/code.ys scripts/multivar.rep/code.ys.def scripts/multivar.rep/makemulti.ys scripts/multivar.rep/sparsenomial.ys scripts/multivar.rep/sparsetree.ys scripts/multivar.rep/sparsetree.ys.def scripts/newly.rep/code.ys scripts/newly.rep/code.ys.def scripts/nintegrate.rep/code.ys scripts/nintegrate.rep/code.ys.def scripts/numbers.rep/GaussianIntegers.ys scripts/numbers.rep/GaussianIntegers.ys.def scripts/numbers.rep/NumberTheory.ys scripts/numbers.rep/NumberTheory.ys.def scripts/numbers.rep/code.ys scripts/numbers.rep/code.ys.def scripts/numbers.rep/nthroot.ys scripts/numbers.rep/nthroot.ys.def scripts/numbers.rep/om.ys scripts/odesolver.rep/code.ys scripts/odesolver.rep/code.ys.def scripts/openmath.rep/code.ys scripts/openmath.rep/code.ys.def scripts/orthopoly.rep/code.ys scripts/orthopoly.rep/code.ys.def scripts/packages.ys scripts/padic.rep/code.ys scripts/padic.rep/code.ys.def scripts/patterns.rep/code.ys scripts/patterns.rep/code.ys.def scripts/physics.rep/quantum/clebsch-gordan.ys scripts/physics.rep/quantum/clebsch-gordan.ys.def scripts/plots.rep/backends-2d.ys scripts/plots.rep/backends-3d.ys scripts/plots.rep/code.ys scripts/plots.rep/code.ys.def scripts/plots.rep/plot2d.ys scripts/plots.rep/plot2d.ys.def scripts/plots.rep/plot3d.ys scripts/plots.rep/plot3d.ys.def scripts/predicates.rep/code.ys scripts/predicates.rep/code.ys.def scripts/probability.rep/code.ys scripts/probability.rep/code.ys.def scripts/products.rep/code.ys scripts/products.rep/code.ys.def scripts/pslq.rep/code.ys scripts/pslq.rep/code.ys.def scripts/r_form.rep/code.ys scripts/r_form.rep/code.ys.def scripts/rabinmiller.rep/code.ys scripts/rabinmiller.rep/code.ys.def scripts/radsimp.rep/code.ys scripts/radsimp.rep/code.ys.def scripts/random.rep/code.ys scripts/random.rep/code.ys.def scripts/rational.rep/code.ys scripts/rational.rep/code.ys.def scripts/simplify.rep/code.ys scripts/simplify.rep/code.ys.def scripts/simplify.rep/factorial.ys scripts/simplify.rep/factorial.ys.def scripts/solve.rep/code.ys scripts/solve.rep/code.ys.def scripts/specfunc.rep/bernou.ys scripts/specfunc.rep/bernou.ys.def scripts/specfunc.rep/bessel.ys scripts/specfunc.rep/bessel.ys.def scripts/specfunc.rep/code.ys scripts/specfunc.rep/code.ys.def scripts/specfunc.rep/gamma.ys scripts/specfunc.rep/gamma.ys.def scripts/specfunc.rep/gammaconst.ys scripts/specfunc.rep/gammaconst.ys.def scripts/specfunc.rep/om.ys scripts/specfunc.rep/zeta.ys scripts/specfunc.rep/zeta.ys.def scripts/standard.ys scripts/standard.ys.def scripts/statistics.rep/distributions.ys scripts/statistics.rep/distributions.ys.def scripts/statistics.rep/hypothesystest.ys scripts/statistics.rep/hypothesystest.ys.def scripts/statistics.rep/incompletegamma.ys scripts/statistics.rep/incompletegamma.ys.def scripts/statistics.rep/randomtest.ys scripts/statistics.rep/regression.ys scripts/statistics.rep/regression.ys.def scripts/statistics.rep/statistics.ys scripts/statistics.rep/statistics.ys.def scripts/stats.rep/code.ys scripts/stats.rep/code.ys.def scripts/stdarith.ys scripts/stdarith.ys.def scripts/stdfuncs.rep/code.ys scripts/stdfuncs.rep/code.ys.def scripts/stdfuncs.rep/elemfuncs.ys scripts/stdfuncs.rep/elemfuncs.ys.def scripts/stdfuncs.rep/numerical.ys scripts/stdfuncs.rep/numerical.ys.def scripts/stdfuncs.rep/nummethods.ys scripts/stdfuncs.rep/nummethods.ys.def scripts/stdfuncs.rep/om.ys scripts/stdopers.ys scripts/stubs.rep/code.ys scripts/stubs.rep/code.ys.def scripts/stubs.rep/om.ys scripts/substitute.rep/code.ys scripts/substitute.rep/code.ys.def scripts/sums.rep/code.ys scripts/sums.rep/code.ys.def scripts/sums.rep/om.ys scripts/trigsimp.rep/code.ys.def scripts/univar.rep/Cyclotomic.ys scripts/univar.rep/Cyclotomic.ys.def scripts/univar.rep/code.ys scripts/trigsimp.rep/code.ys.def scripts/univar.rep/Cyclotomic.ys scripts/univar.rep/Cyclotomic.ys.def scripts/univar.rep/code.ys scripts/sums.rep/taylor.ys scripts/sums.rep/taylor.ys.def scripts/sums.rep/taylor3.ys scripts/sums.rep/taylor3.ys.def scripts/tensor.rep/code.ys scripts/tensor.rep/code.ys.def scripts/testers.rep/code.ys scripts/testers.rep/code.ys.def scripts/texform.rep/code.ys scripts/texform.rep/code.ys.def scripts/transforms.rep/code.ys scripts/trigsimp.rep/code.ys.def scripts/univar.rep/Cyclotomic.ys scripts/univar.rep/Cyclotomic.ys.def scripts/univar.rep/code.ys scripts/transforms.rep/code.ys.def scripts/trigsimp.rep/code.ys scripts/trigsimp.rep/code.ys.def scripts/univar.rep/Cyclotomic.ys scripts/univar.rep/Cyclotomic.ys.def scripts/univar.rep/code.ys scripts/univar.rep/code.ys.def scripts/univar.rep/sparse.ys scripts/univar.rep/sparse.ys.def scripts/univar.rep/sturm.ys scripts/univar.rep/sturm.ys.def scripts/yacasinit.ys) if (ENABLE_CYACAS) install (DIRECTORY scripts/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/yacas/scripts COMPONENT app) endif () if (ENABLE_DOCS) add_subdirectory (docs) add_subdirectory (man) endif() if (ENABLE_JYACAS) add_subdirectory (jyacas) endif () if (ENABLE_CYACAS) add_subdirectory (cyacas) endif () if (ENABLE_CYACAS OR ENABLE_JYACAS) add_subdirectory (tests) endif () ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at teoretyk@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: COPYING ================================================ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ================================================ FILE: ChangeLog ================================================ Changes are none, there is only the now. ================================================ FILE: README.rst ================================================ ===== yacas ===== .. image:: https://img.shields.io/badge/license-LGPL--2.1%2B-blue.svg :target: ./COPYING .. image:: https://ci.appveyor.com/api/projects/status/r8gm1gdk61qe4rgd?svg=true :target: https://ci.appveyor.com/project/grzegorzmazur/yacas .. image:: http://readthedocs.org/projects/yacas/badge/?version=latest :target: http://yacas.readthedocs.org/en/latest/?badge=latest .. image:: https://api.codacy.com/project/badge/Grade/a66fdf5a0140492f9c6eee6c5ba18bd4 :target: https://www.codacy.com/manual/teoretyk/yacas?utm_source=github.com&utm_medium=referral&utm_content=grzegorzmazur/yacas&utm_campaign=Badge_Grade .. image:: https://codecov.io/gh/grzegorzmazur/yacas/branch/master/graph/badge.svg :target: https://codecov.io/gh/grzegorzmazur/yacas Yacas (Yet Another Computer Algebra System) is a small and highly flexible general-purpose Computer Algebra System (CAS). The syntax uses an infix-operator grammar parser. The distribution contains a small library of mathematical functions, but its real strength is in the language in which you can easily write your own symbolic manipulation algorithms. The core engine supports arbitrary precision arithmetic and is able to execute symbolic manipulations on various mathematical objects by following user-defined rules. For detailed information on yacas features and usage, see ``_. ===== who is yacas for? ===== This versatile Computer Algebra System (CAS) was developed to cater to a broad audience, primarily consisting of mathematicians, engineers, and students. It provides a user-friendly platform for performing symbolic mathematical computations, solving intricate equations, all accessible via a command-line interface. Furthermore, it serves as a free alternative to commercial CAS software. For mathematics enthusiasts (probably less than 1% of the population), this tool offers the capability to conduct advanced mathematical manipulations and solve complex equations, making it valuable for research purposes and even recreational mathematical exploration. On the other hand, students can benefit from its educational potential, using it as an open-source resource to learn and practice mathematics while experiencing the advantages of an open-source product like Yacas. ===== Getting Started ===== Step by step guide to understand what yacas is about and start using it ``_ ===== Downloads ===== Yacas is available for a variety of platforms. See ``_ for binary packages and installation instructions. ===== Screenshots ===== For a preview on how yacas looks like ``_ ===== Contact ===== Report bugs or great enhancements ideas to our issue tracker ``_ We have a forum to talk math! ``_ FAQ ``_ Yacas is distributed under the GNU LESSER GENERAL PUBLIC LICENSE v2.1 or, at your discretion, any later version. ================================================ FILE: TODO ================================================ TODO: - Manual titles do not correspond with the manual you go to. - Ceil, Round and Floor, also try to force to a number. - From Laurent Debacker: In file scripts/integrate.rep/code.ys, shouldn't the IntFunc(x,(_x)^(-1),Ln(x)); be IntFunc(x,(_x)^(-1),Ln(Abs(x))); My motivation is based on http://metric.ma.ic.ac.uk/integration/techniques/indefinite/standard-integrals/integral-of-one-over-x/index.html . - Remove the examples directory from the scripts directory, placing them somewhere else to reduce jar file size. - Use reflection to look up methods, will make the jar file smaller. - make the default read-eval-print loop print to out on the go, at least for the off-line version. - do a cleanup of the "ref" manual, first pass to throw away functions that should not have been there in the first place. - second chapter in refprog titled "Programming" has way too many functions - chapter "List operators" has way too many function entries. - chapter "Control flow" has entries relating only to the off-line version - chapter "predicates" has way too many function entries. - chapter "Input/output and plotting" has way too many function entries. - chapter "Number theory" needs to be cleaned up. - do a cleanup of the other books also - scripts/examples/ do somewhere else? - examples should have their own tests - Test suite fails on Java version. We *have* to make the test suite more lenient. - Remove Fast* (does not seem to be used anywhere). FastArcSin, FastAssoc, FastIsPrime, FastLog, FastPower do seem to be used. - get rid of the Ortho?Sum functions, replace with just one? - (find other ...Num functions) - NewtonNum - Future, change name of builtin functions that are not directly accessible to outside to have prefix Builtin'... - Skim through Math... functions, renaming them to Builtin'... - manuals, provide as zip files? more people can use unzip than can use untar. - cos(arccos(x)) -> x+k*2*pi etc - try if I can't change the format of numbers from 0.xxx to x.xxxx, is more natural - make plain site not too wide also - Move brackets slightly down in tex form pretty renderer, especially when what they bracket is not too big. - step-by-step solver possible? - screenshots, explanation of how to use, demo, tipbox, or *something*, to persuade people to enter something in the search field - carefully change things so that the scripts do not have things like "N(Eval(" any more (just grep on it). 1) Documentation improvements - examples embedded in the manual - document ":test" to run test code from article - link to mark-up documentation from the editors. - what is Yacas? How did it come into existence? Why did I write it? Who is it for? - mention the use of lists for passing multiple arguments. ============================================================================================================ - document the algorithms used, and expand on all of the functions currently implemented. - separate manual chapter on tensors. (Serge? Is it going to change?). TSimplify and TExplicitSum, TD, X - document the source code. - document HoldArg in combination with <-- (or actually remove HoldArg? I want to depreciate UnFence/HoldArg in favor of macros) - document II, ReII, ImII, IsComplexII - document ExpressionDepth, PAdicExpandInternal, GetPrimeFactors, Rem, Roots, Apart, Together - document UnHoldable, GcdReduce, ApplyPure, DestructiveAppendList, Pattern'Matches, Pattern'Create, RuleBaseDefined, Lambda (in combination with Apply), Primes, MapArgs, Substitute, - document %, |, &, ^, if, else (else binds to the last if) - document DivPoly, RootsWithMultiples, - document OdeSolve - document Dimensions, IsSquareMatrix, Tr. - document Deriv, Berlekamp, ExtendedEuclidean, ExtendedEuclideanMonic - document IsVariable - document the fact that VarList can also be called with a second argument, a filter predicate. - document Extended predicates in the pattern matcher (needs to be explained). - document DefaultTokenizer() - document XmlTokenizer, XmlExplodeTag - document BSearch, FindIsq Search for a zero in a monotonously growing function. BSearch returns -1 if not found, FindIsq returns the insertion point. - document MultiDivide, MultiGcd, Groebner - document DefLoadFunction - document CharString (input integer, output a string with one char, using the ascii code passed in). - document FloatIsInt - document Explain what is destructive about the Destructive... routines, why they are there, and when to use them. - document Do slightly more on pure functions, to show why they are useful. Show for example Select. - document Explain what Simplify currently does (internal algorithm). - document The PcreLexer and PcreNextToken functions - document Small summary of regular expressions syntax accepted. - document Html... commands. - document some blurb on the pattern matching/multivirtual functionality. - Clean up integration code, and document algorithm used. - document the extra Is... predicates for matrices that was added by Jonathan - document threaded use of integration 2) Web site improvements - allow saving multiple programs in cookies - work through mommies feedback - computer calculations made easy zou ik in lijn met het logo plaatsen liefst in lijn met de groene balletjes. Nu zweeft het een beetje los. - Get Yacas en contact us is goed, maar ik zou het wat lager plaatsen in lijn met de tabs, maar wel zo laten als tekst links. - Explain that a connection to the server is not needed, and that Yacas can be run off-line (with a link to a download of the Yacas web site). ============================================================================================================ - should I reconsider the way things are compressed? tgz? Why not zip? - when leaving codeedit page, ask to remember code? - think through wat it would look like if you could add content - make all screens go 100% (edit, tutorial?) or at least center? - create a clickable program snippet that is other than a one-liner (?) - ideally programs should be uploaded to the datahub from the example pages themselves, and not from recent.html, but for some reason that did not work. When going from deeply-linked, trying it out does not work any more and editing it also not. - make descr/view/edit pages not reload, but refresh content dynamically - In the tutorial, at "Solve", show how to verify that results are correct 3) Research - Scan through my articles - scan through examples already in examples directory in scripts dir - take a look at Axiom code - take a look at Maxima code ============================================================================================================ - Think through series of articles on tensors. - Quaternions example? - Example: the logarithmic derivative example from Fateman is nice. - example: inverse, integrate taylor of 1/f' - example: generating a polynomial solution for an ordinary DE - For fun: try to understand Hensel lifting, and can it be made to apply to say Feynman diagrams? 5) Math improvements ============================================================================================================ - allow control over formatting of floats. - bumping up a version number seems to force a recompile of all the C++ files, config.h rewritten or so? - make all the code more consistent, assuming that variables are real-valued. - remove use of UnFence/HoldArg in favor of macros - after use of UnFence/HoldArg has been removed, remove support for it - local transforms: postpredicates do not seem to work any more. - pattern matcher that can work on rings - Change the system to use the II way of dealing with complex numbers in favor of the Complex(r,i) construct. - When the change to the II way of doing complex numbers is finished, add it to the tutorial (if not already there), and change the manual accordingly - replace perl code in favor of C++ code, easier to maintain. - sparserep from multi, use for uni too - lists/arrays interchangable - remove all uses of local files/directories. - global var access, test code using a function to return a list of global variables. - Clean up Solve code, and document algorithm used. - remove the final references to stdlib in the code. - put Nl() in a common place (if it is still defined in different places or an odd place). - test Apart for polys. This might have to be adjusted by adding using the same mechanism used for the integer version. - Taylor on functions containing Abs/Sign can not be trusted (no idea what I meant by that, but worth checking). - Define the Local,.. functions based on their Macro counterparts, in the scripts. - also define a Head and Tail for arrays, and append/concat/ insert/delete/copy. This will ease swapping between lists and arrays. - Allow for type convertors in pattern matchers. For instance: IsUniVar, should be combined with CanBeUni and NormalForm to get the correct one back. - A RuleBaseDefined-like function that returns a list of defined arities. - FindZeroes (polynoms and other functions) - redivide some code ('newly') - make suchthat more powerful, so it simplifies sin(x)=cos(x) to tan(x)=1 to x=Pi/4 - groebner bases - see if using arrays for matrices speeds up things. - Fix CanBeUni so that it deals correctly with 1/c - EquateCoefs equate coefficients in two polys, and return as list. - document /. and /:: with <- - allow solve to return a list usable in /. - matrix^negative is inverse^positive 6) Bugs: ============================================================================================================ - some limits not working correctly when using infinity: Limit(x,Infinity) Zeta(x) - factorize not checking for correctness of arguments: Factorize(Infinity), Factorize(-1) - Limit(x,0)D(x,2)Sin(x)/x never terminates (or rather takes a very long time), which in turn causes Taylor(x,0,5)Sin(x)/x to never terminate. - Limit(x,Infinity) x^n/Ln(x) returns n*Infinity, should be Infinity - Limit(x,0,Right) x^( Ln(a)/(1+Ln(x)) ) returns 1, should be "a" - [A:={{1,2,3,4},{0,1,2,3},{0,0,1,2},{I,0,I,I}}; EigenValues(A);] hangs - L'Hopital's theorem is not always the correct thing to do. There is a paper by Richardson, Salvy et al "Asymptotic expansions of exp-log functions" that may be helpful. - TrigSimpCombine(x^500)' exhausts the stack - 'Solve(Exp(x^2)==Exp(x),x)' yields {} instead of {0,1}. - BUG: InverseTaylor not working correctly for Sin and Tan??? - BUG: complex^float. - Mod(a,b) generates some "UniVariate()" calls if a and b are undefined (I expected it to return unevaluated). If one of them is defined, and the other undefined, Mod() returns some numbers. Mod(x,-3) returns unevaluated. I'm not sure what the "correct" meaning of Mod is for negative moduli bases, but the answer should in any case be non-negative. Mod(a,b) is defined as the smallest non-negative number c such that a-c is divisible by b. - Simplify(4-x-y) returns 4-y-x, Simplify(4-y-x) returns 4-x-y - Functions to be implemented in the Java version still: - LispFastMod - YacasDllLoad - LispPatchLoad - LispPatchString - Some more functions that are defined in yacasmain.cpp: Exit, IsExitRequested, HistorySize, StaSiz, IsPromptShown, ReadCmdLineString, FileSize - LispDefaultTokenizer - LispCommonLispTokenizer - LispXmlTokenizer - LispExplodeTag - LispCustomEval - LispCustomEvalExpression - LispCustomEvalResult - LispCustomEvalLocals - LispCustomEvalStop - LispTraceRule - LispTraceStack - command line flags for Java console version, useful for doing the test scripts - Supporting the default read-eval-print loop from script in Java? - Run the tests from Java - Give some performance statistics on comparison between Java and C++ 8) Unsorted: ============================================================================================================ - Search for defines I want to remove - Document TeXFormMaxPrec() - Document DefFileList() - check that unnecessary scripts are not loaded unnecessarily (in debug mode?) - Document FormulaMaxWidth() - Document SetFormulaMaxWidth(width) - Document the debugging facilities in the debug version, warnings on setting global variables etcetera. - Global variables are still used in the wester test file - Global variables are still used in the scripts that build the manuals - Global variables are still used in the scripts that create the plugin stubs - Global variables are still used in the scripts that compile/create for example libmath.cpp - Is there not enough in common between the different files platfileio.h that we should perhaps consider merging them? - For N, Verbose, etcetera, in stead of LocalSymbols guarding scope, perhaps a macro that generalizes the concept (with getters and setters, for a type of expandable singleton). - have the application work in a directory structure that is identical to the source tree. --rootdir should be more general (set it and you can find the documentation also, etcetera). - plotting functions are extremely verbose, this code needs to be reduced I feel - other os-ish modules that I think are ugly, ShowPS ? Tries to write to /tmp/? - examples direcory in scripts/, needed? - allow sending openmath expressions and receiving them from a socket. - allow parsing without having to require a ; - removing ] from output - Remove MacroSet/MacroClear and friends in favor of macros? makes the whole system simpler, and easier to compile. - Erf does not work for numbers larger than one but not too large. - http://www.causascientia.org/math_stat/Dists/Compendium.pdf - remove TODOs in the source code - document as of yet undocumented functions - Try Yacas from some other applet, as a scripting language - Try out MapReduce - allow for a custom REP loop in server mode (would actually be trivial when sockets are defined in Yacas language) - Mention MultiGcd in the documentation where polynomial operations are explained. - make sure there are no collisions (axiom link in links.html for example) ??? - change all references to LISP in to YACAS, and Lisp in to Yacas - univar.rep/Cyclotomic.ys is the only file to start with a capital (perhaps change to lower case?) - some garbage (double defined functions) I'd like to remove from univar - Taylor series expansion of Tan is slow, use other form for derivative? - Solve: see if I can recreate HEQS? - YacasInterpreter: also allow it to work from an applet? - Write test for Solve({mean==(A/(A+B)),variance==((A*B)/(((A+B)^2) * (A+B+1)))},{A,B}) - There are warnings about YacasBase not having a virtual destructor, problem? - document the behavior of underscores in Yacas. - Clebsch-Gordan coefficients: - Get Clebsch-Gordan code in to the main Yacas distribution. - Test code for Clebsch-Gordan - documentation for Clebsch-Gordan - document *how* the random number generators work. - -pc flags should also withhold the In> and Out> printing. Document that you need to use --read-eval-print "" - http://centaur.maths.qmul.ac.uk/Computer_Algebra/MathAlgs/mathalgs.pdf - restructure the documentation (there are a lot of unfinished parts written by Ayal). - rewrite anumber, and document it this time. - implement precision tracking the way Serge wants it, in the anumber version of BigNumber - slowness of Taylor, due to its trivial implementation. Perhaps we should do something about this as soon as we have series calculus. - Solve is way too simplistic. - (Is this still true?) MatchAtom still compares atoms by string representation! It should raise an error if you define a pattern with a float in it. ============================================================================================================ 9) Article fodder: UI to search solution spaces ============================ Computers have made many laborious tasks easier to do. You can look up mathematical things in a database-ish way, or have the computer do repetitive work. There are more things computers are good at. Because you can design a user interface, you can design how it interacts with humans, you can effectively design a custom tool for a task. When I did my internship (high-energy physics, Zeus, 1995-1996, at NIKHEF H) I used a user interface to get more results. The task at hand with high-energy physics is as follows; you have this massive accelerator that accelerates particles in a tube. The accelerated particle beams collide, and out of the collision come other particles. The particles that come out of it can tell you something about the structure of the particles that collided. Now at the point where the collision takes place people place what they call a detector. This detector detects particles coming from the collision. The collisions occur at enormous rates, so you get an enormous amount of data coming from these detectors. Any way, the data is filtered a bit (the amount of data coming from these detectors is so vast that one can not possibly hope to capture all of it, so electronics boards are designed to be able to handle the high bandwidth of data and filter out the events for which it is absolutely sure that the researchers will not be interested in it, reducing the amount of data captured), and then ends on a harddisk somewhere, in what they call (or used to call, don't know how it works nowadays) ntuples, essentially one big database table with rows of records, each record with some fields. Each row is an isolated event that might be of interest. Now the trick is to make a selection of the events, and plot a certain number. For example, one could take all the events where the electron (one of the incoming particles) scattered heavily backwards, and then plot the mass of the whole system, as in a histogram, where you accumulate the results of events with mass between two values in one bin, mass between other values in the next bin, etcetera. You would then see a sea of noise, with hopefully a peak in it, which would be called a "resonance", and would indicate that there had been a short-lived particle with that mass. The narrower the peak, the longer-lived the particles. The wider the peak, the shorter-lived the particles. This way you could measure the speed at which they decayed, which you can also calculate from theory sometimes, or at least use as an input parameter for theory. And you could measure the precise point of the top, so as to give you the mass of the particle. And you could count the number of events that were in the peak, and again compare that to theory, which should be able to give a prediction of the amount of events that were observed given the intensity of the beams colliding against each other. The trick would be to find the area where the resonance (the peak) should be, and try to design filters that reduce the background noise while keeping as much as possible of the signal. The filters would be simple things (often referred to as cuts, as they cut out a part of the data). For example, you could select all the events for which a specific value in one of the fields of the ntuple was larger than a certain value. Or smaller than a specific value. Large part of the work consisted of just trial-and-error, finding the good cuts to apply as to get the best view on the resonance. The cut to apply was the real information being sought. It required hard work, putting in many many many hours. The more hours you worked, the more likely you were to find something interesting. Being smart is not enough in such a case, as luck plays a big role (as they say, luck is when opportunity meets preparation). After you found the best cuts to apply to the data, it was surprisingly little information you needed to communicate. It could be as little as just a few conditionals, selecting all the events with, say, a detected electron, and where the virtual photon had a larger energy than such and so, and ... Surprisingly hard work for so little information. One would then proceed to get an estimate of the curve representing the noise, and subtract that from the data, to arrive at the pure signal. A good estimate of the total noise is then subtracted from the total data in what is hoped to then be the resulting signal of the resonance being sought. The task is thus essentially just to count how often something happened, and to try to make a wise selection of the events to look at. One problem I encountered during my internship was that due to the fact that there was just such a vast amount of data, each time I wanted to change a cut, you had to wait forever (10 minutes sometimes), for the result. You would wander off and do something else, and come back to the window where you were trying the cut, wondering what it was again you were trying out. It all just moved very slow. So one weekend I resolved to make a nice little tool to make my life easier. The entire group worked on a Silicon Graphics workstation at that time, which apparently had cost the equivalent of 150,000.00 euros, and carried an astonishing 256 megabytes of RAM. Twelve people worked on that. Chances are you are now reading this article on a computer that cost a fraction of that machine, and has many times more memory than we had back then. And we were doing cutting edge research! But I digress. I used what knowledge I had already gleaned from the data to make a stricter selection on the data. What resulted was something like 38 megabytes of data remaining. What I then did was load that all in to memory (I waited until every one had gone home so I had the full system to myself, one advantage of working on big iron). In addition, I kept an index of each field, and sorted the records per that field, in that index. Now, I created a little user interface that would show a graph, histogram, of the counts of number of events per bin. And I defined scrollbars that allowed me to define ranges from within to select data. Those were effectively two cuts, one to the left and one to the right, limiting the amount to fall within a range of two values, a - One-off tasks, completable in a few hours - A look at Google Analytics - Example: RootsOfUnity (nice example of threading): Exp(2*Pi*I*(1 .. n)/n) - Example: Average (nice example of threading): Average(list_IsList) <-- Add(list)/Length(list); - Example: Fibonacci series, Lucas series. - Verify( Fibonacci(242), 168083057059453008835412295811648513482449585399521 ); - Verify( Fibonacci(6,.5), 2.03125 ); - Verify( Fibonacci(3,.5), 1.25 ); - Article: rant on strong typing versus test code - Article on splitting documentation between the two target audiences "user" and "maintainer". - poking fun at systems by caricaturizing their properties ================================================ FILE: appveyor.yml ================================================ branches: only: - master - develop skip_tags: true platform: - x64 configuration: - Release environment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 CMAKE_GENERATOR: "Visual Studio 16 2019" ENABLE_CYACAS_GUI: On ENABLE_CYACAS_KERNEL: On QTDIR: C:\Qt\5.15.2\msvc2019_64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 CMAKE_GENERATOR: "Visual Studio 17 2022" ENABLE_CYACAS_GUI: Off ENABLE_CYACAS_KERNEL: On QTDIR: C:\Qt\5.15.2\msvc2022_64 - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu2004 CMAKE_GENERATOR: "Ninja" ENABLE_CYACAS_GUI: Off ENABLE_CYACAS_KERNEL: On QTDIR: $HOME/Qt/5.15.2/gcc_64/bin - APPVEYOR_BUILD_WORKER_IMAGE: macos-bigsur CMAKE_GENERATOR: "Xcode" ENABLE_CYACAS_GUI: Off ENABLE_CYACAS_KERNEL: Off QTDIR: $HOME/Qt/5.15.2/clang_64/bin install: - cmd: if not exist C:\Tools\vcpkg\installed\x64-windows\bin ( cd c:\tools\vcpkg & vcpkg install boost-filesystem:x64-windows & vcpkg install boost-date-time:x64-windows & vcpkg install boost-serialization:x64-windows & vcpkg install boost-uuid:x64-windows & vcpkg install boost-dll:x64-windows & vcpkg install openssl:x64-windows & vcpkg install zeromq:x64-windows & vcpkg install jsoncpp:x64-windows & vcpkg install cppzmq:x64-windows & vcpkg integrate install ) - sh: if [ "$APPVEYOR_BUILD_WORKER_IMAGE" == "Ubuntu2004" ]; then sudo apt-get update -qq; sudo apt-get install -qq libboost-all-dev libssl-dev libjsoncpp-dev libzmq3-dev; fi - sh: if [ "$APPVEYOR_BUILD_WORKER_IMAGE" == "macos-bigsur" ]; then brew update; brew upgrade; brew install boost jsoncpp zeromq; fi cache: - c:\tools\vcpkg\installed\ -> appveyor.yml before_build: - cmd: cd %APPVEYOR_BUILD_FOLDER% - cmd: cmake -H. -Bbuild -G "%CMAKE_GENERATOR%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DENABLE_CYACAS_KERNEL=%ENABLE_CYACAS_KERNEL% -DENABLE_CYACAS_UNIT_TESTS=Off -DENABLE_CYACAS_BENCHMARKS=Off -DENABLE_CYACAS_GUI=%ENABLE_CYACAS_GUI% -DCMAKE_PREFIX_PATH="%QTDIR%" -DCMAKE_INSTALL_PREFIX=%APPVEYOR_BUILD_FOLDER%\install - sh: cd $APPVEYOR_BUILD_FOLDER - sh: cmake -H. -Bbuild -G $CMAKE_GENERATOR -DCMAKE_BUILD_TYPE=Release -DENABLE_CYACAS_KERNEL=$ENABLE_CYACAS_KERNEL -DENABLE_CYACAS_UNIT_TESTS=Off -DENABLE_CYACAS_BENCHMARKS=Off -DENABLE_CYACAS_GUI=$ENABLE_CYACAS_GUI -DCMAKE_PREFIX_PATH="$QTDIR" -DCMAKE_INSTALL_PREFIX=$APPVEYOR_BUILD_FOLDER/install build_script: - cmd: cd %APPVEYOR_BUILD_FOLDER%\build - cmd: cmake --build . --config Release --target install - sh: cd $APPVEYOR_BUILD_FOLDER/build - sh: cmake --build . --config Release --target install test_script: - cmd: cd %APPVEYOR_BUILD_FOLDER%\build - cmd: ctest -C Release - sh: cd $APPVEYOR_BUILD_FOLDER/build - sh: ctest -C Release after_build: - cmd: cd ..\install - cmd: 7z a yacas.zip * - sh: cd ../install - sh: zip -r yacas.zip * artifacts: - path: install/yacas.zip name: yacas ================================================ FILE: build.xml ================================================ jyacas build file ================================================ FILE: cyacas/CMakeLists.txt ================================================ if (APPLE) set(CMAKE_MACOSX_RPATH 1) set(CMAKE_INSTALL_FRAMEWORK_PREFIX "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.") set(CMAKE_INSTALL_BUNDLE_PREFIX "/Applications" CACHE STRING "Directory to install application bundles to.") endif() if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang OR CMAKE_CXX_COMPILER_ID STREQUAL AppleClang) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -fPIC") elseif (MSVC) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4800") add_definitions(-DYACAS_NO_CONSTEXPR -DYACAS_NO_ATOMIC_TYPES -DYACAS_UINT32_T_IN_GLOBAL_NAMESPACE) endif () if (CMAKE_SYSTEM_NAME STREQUAL Emscripten) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s DISABLE_EXCEPTION_CATCHING=0 -s ASSERTIONS=1 -s EXTRA_EXPORTED_RUNTIME_METHODS=['cwrap'] -s ALLOW_MEMORY_GROWTH=1") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --embed-file ${PROJECT_SOURCE_DIR}/scripts@/share/yacas/scripts") endif () include(CheckIPOSupported) check_ipo_supported(RESULT IPO_SUPPORTED) add_library(coverage_config INTERFACE) if (ENABLE_CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") # Add required flags (GCC & LLVM/Clang) target_compile_options(coverage_config INTERFACE -g # generate debug info --coverage # sets all required flags ) if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) target_link_options(coverage_config INTERFACE --coverage) else () target_link_libraries(coverage_config INTERFACE --coverage) endif () endif () add_subdirectory (libyacas_mp) add_subdirectory (libyacas) if (ENABLE_CYACAS_CONSOLE) add_subdirectory (yacas) endif () if (ENABLE_CYACAS_GUI) add_subdirectory (yacas-gui) endif () if (ENABLE_CYACAS_KERNEL) add_subdirectory (yacas-kernel) endif () if (ENABLE_CYACAS_XEUS) add_subdirectory (xeus-yacas) endif () ================================================ FILE: cyacas/libyacas/CMakeLists.txt ================================================ configure_file ( "config/yacas/yacas_version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config/yacas/yacas_version.h" ) set (SOURCES src/associationclass.cpp src/deffile.cpp src/infixparser.cpp src/lispatom.cpp src/lispenvironment.cpp src/lispeval.cpp src/lisperror.cpp src/lispio.cpp src/lispobject.cpp src/lispparser.cpp src/lispuserfunc.cpp src/mathcommands.cpp src/mathuserfunc.cpp src/standard.cpp src/stdfileio.cpp src/arggetter.cpp src/stringio.cpp src/tokenizer.cpp src/yacasapi.cpp src/lispevalhash.cpp src/patterns.cpp src/patternclass.cpp src/substitute.cpp src/mathcommands2.cpp src/mathcommands3.cpp src/mempool.cpp src/errors.cpp src/patcher.cpp src/xmltokenizer.cpp src/anumber.cpp src/yacasnumbers.cpp src/numbers.cpp src/platmath.cpp src/lisphash.cpp) set (HEADERS include/yacas/anumber.h include/yacas/anumber.inl include/yacas/arggetter.h include/yacas/arrayclass.h include/yacas/associationclass.h include/yacas/corefunctions.h include/yacas/deffile.h include/yacas/errors.h include/yacas/evalfunc.h include/yacas/genericobject.h include/yacas/GPL_stuff.h include/yacas/infixparser.h include/yacas/lispatom.h include/yacas/lispenvironment.h include/yacas/lisperror.h include/yacas/lispeval.h include/yacas/lispevalhash.h include/yacas/lispglobals.h include/yacas/lisphash.h include/yacas/lispio.h include/yacas/lispobject.h include/yacas/lispoperator.h include/yacas/lispparser.h include/yacas/lispstring.h include/yacas/lispuserfunc.h include/yacas/mathcommands.h include/yacas/mathuserfunc.h include/yacas/mempool.h include/yacas/noncopyable.h include/yacas/numbers.h include/yacas/patcher.h include/yacas/patternclass.h include/yacas/patterns.h include/yacas/platfileio.h include/yacas/platmath.h include/yacas/refcount.h include/yacas/standard.h include/yacas/standard.inl include/yacas/stringio.h include/yacas/string_utils.h include/yacas/substitute.h include/yacas/tokenizer.h include/yacas/utf8/core.h include/yacas/utf8/checked.h include/yacas/utf8/unchecked.h include/yacas/utf8.h include/yacas/xmltokenizer.h include/yacas/yacas.h) add_library (libyacas ${SOURCES} ${HEADERS}) set_target_properties (libyacas PROPERTIES OUTPUT_NAME "yacas" INTERPROCEDURAL_OPTIMIZATION ${IPO_SUPPORTED}) target_include_directories (libyacas PUBLIC include "${CMAKE_CURRENT_BINARY_DIR}/config") target_link_libraries (libyacas PUBLIC libyacas_mp coverage_config) install (TARGETS libyacas LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT app) install (DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT dev) install (FILES "${CMAKE_CURRENT_BINARY_DIR}/config/yacas/yacas_version.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/yacas COMPONENT dev) # if (APPLE) # add_library (libyacas_framework SHARED ${SOURCES} ${HEADERS}) # set_target_properties(libyacas_framework PROPERTIES OUTPUT_NAME "yacas" VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION} FRAMEWORK ON) # target_link_libraries(libyacas_framework libyacas_mp) # target_include_directories (libyacas_framework PUBLIC include "${CMAKE_CURRENT_BINARY_DIR}/config") # add_custom_command(TARGET libyacas_framework POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/scripts $/Resources/scripts) # add_custom_command(TARGET libyacas_framework POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/include $/Headers) # add_custom_command(TARGET libyacas_framework POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_BINARY_DIR}/config $/Headers) # add_custom_command(TARGET libyacas_framework POST_BUILD COMMAND cd "$/../.." && rm -f Headers && ln -s Versions/Current/Headers Headers) # install (TARGETS libyacas_framework FRAMEWORK DESTINATION ${CMAKE_INSTALL_FRAMEWORK_PREFIX} COMPONENT framework) # endif() ================================================ FILE: cyacas/libyacas/config/yacas/yacas_version.h.in ================================================ #ifndef YACAS_VERSION #define YACAS_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ #define YACAS_VERSION_MINOR @PROJECT_VERSION_MINOR@ #define YACAS_VERSION_MICRO @PROJECT_VERSION_PATCH@ #define YACAS_VERSION "@PROJECT_VERSION@" #endif ================================================ FILE: cyacas/libyacas/include/yacas/GPL_stuff.h ================================================ #ifndef YACAS_GPL_STUFF_H #define YACAS_GPL_STUFF_H #define GPL_base_text \ "Yacas is Free Software--Free as in Freedom--so you can redistribute Yacas or\n" \ "modify it under certain conditions. Yacas comes with ABSOLUTELY NO WARRANTY.\n" \ "See the GNU Lesser General Public License (LGPL) version 2.1 or (at your\n" \ "discretion) any later version for the full conditions.\n" #define Yacas_Web_info \ "See http://www.yacas.org/ for more information on yacas. and documentation.\n"\ "Type ?? for help. Or type ?function for help on a function.\n" #define Yacas_help_info \ "Type ?license or ?licence to see the LGPL version 2.1;\n" // This is the full text for systems where the online help (?blah) is available #define GPL_blurb GPL_base_text Yacas_help_info Yacas_Web_info "\n" // This is for systems where online help (?blah) is normally not available #define GPL_blurb_nohelp GPL_base_text Yacas_Web_info "\n" #endif ================================================ FILE: cyacas/libyacas/include/yacas/anumber.h ================================================ #ifndef YACAS_ANUMBER_H #define YACAS_ANUMBER_H #include #include #include #include #include "yacas/mp/zz.hpp" // These define the internal types for the arbitrary precision // number module. The larger they are the better. PlatDoubleWord // should be at least twice as big as PlatWord, to prevent overflowing // during multiplication. typedef std::uint32_t PlatWord; typedef std::uint64_t PlatDoubleWord; typedef std::int64_t PlatSignedDoubleWord; /* Quantities derived from the platform-dependent types for doing * arithmetic. */ #define WordBits (8*sizeof(PlatWord)) #define WordBase (((PlatDoubleWord)1)< { public: ANumber(const std::string& aString,int aPrecision,int aBase=10); ANumber(const yacas::mp::ZZ&, int aPrecision); explicit ANumber(int aPrecision); //TODO the properties of this object are set in the member initialization list, but then immediately overwritten by the CopyFrom. We can make this slightly cleaner by only initializing once. inline ANumber(const ANumber& aOther) : std::vector(), iExp(0),iNegative(false),iPrecision(0),iTensExp(0) { CopyFrom(aOther); } void CopyFrom(const ANumber& aOther); bool ExactlyEqual(const ANumber& aOther); void SetTo(const std::string& aString,int aBase=10); int Precision() const; void SetPrecision(int aPrecision) {iPrecision = aPrecision;} void ChangePrecision(int aPrecision); void RoundBits(); void DropTrailZeroes(); void Expand(); void Negate(); bool IsZero() const; bool IsNegative() const; bool IsEven() const; void Print(std::ostream&, const std::string& prefix) const; public: int iExp; bool iNegative; int iPrecision; int iTensExp; }; inline int ANumber::Precision() const { return iPrecision; } bool BaseLessThan(const ANumber& a1, const ANumber& a2); bool BaseGreaterThan(const ANumber& a1, const ANumber& a2); void BaseDivide(ANumber& aQuotient, ANumber& aRemainder, ANumber& a1, ANumber& a2); void IntegerDivide(ANumber& aQuotient, ANumber& aRemainder, ANumber& a1, ANumber& a2); bool Significant(ANumber& a); int WordDigits(int aPrecision, int aBase); // Operations on ANumber. void Negate(ANumber& aNumber); void ANumberToString(std::string& aResult, ANumber& aNumber, int aBase, bool aForceFloat=false); void Add(ANumber& aResult, ANumber& a1, ANumber& a2); void Subtract(ANumber& aResult, ANumber& a1, ANumber& a2); void Multiply(ANumber& aResult, ANumber& a1, ANumber& a2); void Divide(ANumber& aQuotient, ANumber& aRemainder, ANumber& a1, ANumber& a2); bool GreaterThan(ANumber& a1, ANumber& a2); bool LessThan(ANumber& a1, ANumber& a2); void BaseShiftRight(ANumber& a, int aNrBits); void BaseShiftLeft(ANumber& a, int aNrBits); void NormalizeFloat(ANumber& a2, int digitsNeeded); inline void ANumber::Negate() { iNegative = !iNegative; // FIXME: do we need negative zero? if (IsZero()) iNegative = false; } inline bool ANumber::IsZero() const { return std::all_of(begin(), end(), [](PlatWord a) {return a == 0;}); } inline bool ANumber::IsNegative() const { return iNegative; } inline bool ANumber::IsEven() const { return (front() & 1) == 0; } #include "anumber.inl" #endif ================================================ FILE: cyacas/libyacas/include/yacas/anumber.inl ================================================ #include "anumber.h" /* BaseTimesInt : multiply a with one digit in the range 0..(aBase-1) */ template inline void BaseTimesInt(T& a,PlatDoubleWord aNumber, PlatDoubleWord aBase) { PlatDoubleWord carry=0; const int nr=a.size(); typename T::value_type * aptr = &a[0]; for (int i=0;i inline void WordBaseTimesInt(T& a,PlatDoubleWord aNumber) { PlatDoubleWord carry=0; const int nr=a.size(); typename T::value_type * aptr = &a[0]; for (int i=0;i> WordBits; } if (carry) a.push_back(carry); } template inline void BaseDivideInt(T& a,PlatDoubleWord aNumber, PlatDoubleWord aBase, PlatDoubleWord& aCarry) { const int nr=a.size(); PlatDoubleWord carry=0; typename T::value_type * aptr = &a[0]; for (int i=nr-1;i>=0;i--) { const PlatDoubleWord word = (carry*aBase)+((PlatDoubleWord)(aptr[i])); aptr[i] = word / aNumber; carry= word % aNumber; } //carry now is the remainder aCarry = carry; } /* GrowDigits : add digits to a until it has aDigits digits */ template inline void GrowDigits(T& a, std::size_t aDigits) { if (aDigits <= a.size()) return; a.resize(aDigits, 0); } /* BaseAdd : destructively add aSource to aTarget, in base aBase. */ template inline void BaseAdd(T& aTarget, const T& aSource, PlatDoubleWord aBase) { // Initialize result GrowDigits(aTarget,aSource.size()); aTarget.push_back(0); int nr = std::min(aTarget.size(), aSource.size()); PlatDoubleWord carry=0; const typename T::value_type * sourcePtr = &aSource[0]; typename T::value_type * targetPtr = &aTarget[0]; for (int digit=0;digit inline void WordBaseAdd(T& aTarget, const T& aSource) { // Initialize result GrowDigits(aTarget,aSource.size()); aTarget.push_back(0); int nr = std::min(aTarget.size(), aSource.size()); PlatDoubleWord carry=0; const typename T::value_type * sourcePtr = &aSource[0]; typename T::value_type * targetPtr = &aTarget[0]; for (int digit=0;digit> WordBits); targetPtr[digit] = (typename T::value_type)newDigit; carry = newCarry; } while (carry != 0) { PlatSignedDoubleWord ww = targetPtr[nr]; ww+=carry; targetPtr[nr] = (typename T::value_type)ww; // PDG - cast to avoid compile-time warning carry = ww >> WordBits; nr++; } } template inline void BaseSubtract(T& aResult, T& a2, int offset) { if (a2.IsZero()) return; // Initialize result int nr = a2.size(); typename T::value_type * resultPtr = &aResult[0]; typename T::value_type * a2ptr = &a2[0]; while (a2ptr[nr-1] == 0) nr--; // Subtract on a per-digit basis PlatSignedDoubleWord carry=0; int digit; for (digit=0;digit 0. // Assume aNumber is an integer > 0. // Assume PlatDoubleWord is an integer type. // Will maximum digit (i.e., aBase-1) convert to T::value_type right? //LISPASSERT( (typename T::value_type)(aBase) == (aBase) ); // use aBase instead, to help CTCE aTarget.clear(); while (aNumber != 0) { aTarget.push_back(aNumber%aBase); aNumber/=aBase; } if (aTarget.empty()) aTarget.push_back(0); } // BaseAddMultiply : multiply x and y, and add result to aTarget // inline void BaseAddMultiply(std::string& aTarget, const std::string& x, const std::string& y, PlatDoubleWord aBase) { const unsigned nrx = static_cast(x.size()); const unsigned nry = static_cast(y.size()); GrowDigits(aTarget, nrx + nry + 1); std::string::value_type *targetPtr = &aTarget[0]; const std::string::value_type *xPtr = &x[0]; const std::string::value_type *yPtr = &y[0]; for (unsigned ix = 0; ix < nrx; ix++) { PlatDoubleWord carry = 0; for (unsigned iy = 0; iy < nry; iy++) { const PlatDoubleWord word = static_cast (targetPtr[ix + iy]) + static_cast (xPtr[ix]) * static_cast (yPtr[iy]) + carry; targetPtr[ix + iy] = word % aBase; carry = word / aBase; } targetPtr[ix + nry] += carry; } } template inline void WordBaseAddMultiply(T& aTarget, const T& x, const T& y) { const unsigned nrx=x.size(); const unsigned nry=y.size(); GrowDigits(aTarget,nrx+nry+1); typename T::value_type *targetPtr = &aTarget[0]; const typename T::value_type *xPtr = &x[0]; const typename T::value_type *yPtr = &y[0]; for (unsigned ix=0;ix(targetPtr[ix+iy])+ static_cast(xPtr[ix])* static_cast(yPtr[iy])+carry; targetPtr[ix+iy] = word; carry = word >> WordBits; } const PlatDoubleWord word = static_cast(targetPtr[ix+nry])+carry; targetPtr[ix+nry] = word; assert((word >> WordBits) == 0); } } /* BaseMultiply : multiply x and y, and put result in aTarget */ template inline void BaseMultiply(T& aTarget, const T& x, const T& y, PlatDoubleWord aBase) { aTarget.resize(1); aTarget[0] = 0; BaseAddMultiply(aTarget, x, y, aBase); } template inline void WordBaseMultiply(T& aTarget, const T& x, const T& y) { aTarget.resize(1); aTarget[0] = 0; WordBaseAddMultiply(aTarget, x, y); } template inline bool IsZero(const T& a) { const typename T::value_type *ptr = &a[0]; const typename T::value_type *endptr = ptr + a.size(); while (ptr != endptr) if (*ptr++ != 0) return false; return true; } template inline void WordBaseDivide(T& aQuotient, T& aRemainder, T& a1, T& a2) { // Find the values n and m as described in Knuth II: int n=a2.size(); assert(n>0); assert(a2[n-1] != 0); //a1.size() = m+n => m = a1.size()-n int m = a1.size()-n; assert(m>=0); aQuotient.resize(m+1); //D1: //this calculates d = base/(a2[n-1]+1); PlatDoubleWord d = WordBase/(static_cast(a2[n-1])+1); WordBaseTimesInt(a1, d); WordBaseTimesInt(a2, d); a1.push_back(0); a2.push_back(0); //D2: int j = m; while (j>=0) { //D3: PlatDoubleWord q = (a1[j+n]*WordBase+a1[j+n-1])/a2[n-1]; PlatDoubleWord r = (a1[j+n]*WordBase+a1[j+n-1])%a2[n-1]; REDO: if (q == WordBase || q*a2[n-2] > WordBase*r+a1[j+n-2]) { q = q - 1; r = r + a2[n-1]; if (r < WordBase) goto REDO; } //D4: ANumber sub(aQuotient.Precision()); sub.CopyFrom(a2); WordBaseTimesInt(sub, q); sub.push_back(0); PlatSignedDoubleWord carry; {//Subtract the two //TODO this can be generalized!!!! // // Beware though: this is not a normal subtraction. Only a // certain set of digits ends up being subtracted. // First check if qv isn't too big... carry = 0; for (int digit=0;digit<=n;digit++) { PlatSignedDoubleWord word; word = ((PlatSignedDoubleWord)a1[digit+j]) - ((PlatSignedDoubleWord)sub[digit]) + (PlatSignedDoubleWord)carry; carry=0; while (word<0) { word+=WordBase; carry--; } } if (carry) { q--; sub.CopyFrom(a2); WordBaseTimesInt(sub, q); sub.push_back(0); } carry = 0; for (int digit=0;digit<=n;digit++) { PlatSignedDoubleWord word; word = ((PlatSignedDoubleWord)a1[digit+j]) - ((PlatSignedDoubleWord)sub[digit]) + (PlatSignedDoubleWord)carry; carry=0; while (word<0) { word+=WordBase; carry--; } a1[digit+j] = ((PlatWord)(word)); } } assert(carry == 0); //D5: aQuotient[j] = (typename T::value_type)q; //D7: j--; } //D8: a1.resize(n); PlatDoubleWord carry; BaseDivideInt(a1, d, WordBase,carry); aRemainder.CopyFrom(a1); } inline void ANumber::Expand() { if (iExp+1>int(size())) insert(end(), iExp+1-int(size()), 0); } ================================================ FILE: cyacas/libyacas/include/yacas/arggetter.h ================================================ #ifndef YACAS_ARGGETTER_H #define YACAS_ARGGETTER_H #include "lispenvironment.h" /// Get an argument that should be a short integer int GetShortIntegerArgument(LispEnvironment& aEnvironment, int aStackTop, int iArgNr); #endif ================================================ FILE: cyacas/libyacas/include/yacas/arrayclass.h ================================================ #ifndef YACAS_ARRAYCLASS_H #define YACAS_ARRAYCLASS_H #include "lispobject.h" #include "genericobject.h" #include class ArrayClass final: public GenericClass { public: //required ArrayClass(std::size_t aSize,LispObject* aInitialItem); const char* TypeName() const override; //array-specific std::size_t Size() const; LispObject* GetElement(std::size_t aItem) const; void SetElement(std::size_t aItem,LispObject* aObject); private: std::vector iArray; }; inline ArrayClass::ArrayClass(std::size_t aSize, LispObject* aInitialItem): iArray(aSize, LispPtr(aInitialItem)) { } inline const char* ArrayClass::TypeName() const { return "\"Array\""; } inline std::size_t ArrayClass::Size() const { return iArray.size(); } inline LispObject* ArrayClass::GetElement(std::size_t aItem) const { assert(aItem > 0 && aItem<=iArray.size()); return iArray[aItem-1]; } inline void ArrayClass::SetElement(std::size_t aItem, LispObject* aObject) { assert(aItem > 0 && aItem<=iArray.size()); iArray[aItem-1] = aObject; } #endif ================================================ FILE: cyacas/libyacas/include/yacas/associationclass.h ================================================ /* * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesset General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ /* * File: associationclass.h * Author: mazur * * Created on September 29, 2015, 3:44 PM */ #ifndef ASSOCIATIONCLASS_H #define ASSOCIATIONCLASS_H #include "lispobject.h" #include "genericobject.h" #include "standard.h" #include class AssociationClass final: public GenericClass { public: AssociationClass(const LispEnvironment& env); const char* TypeName() const override; std::size_t Size() const; bool Contains(LispObject* k) const; LispObject* GetElement(LispObject* k); void SetElement(LispObject* k,LispObject* v); bool DropElement(LispObject* k); LispPtr Keys() const; LispPtr ToList() const; LispPtr Head() const; private: class Key { public: Key(const LispEnvironment& env, LispObject* p): value(p), _env(env) {} bool operator == (const Key& rhs) const { return InternalEquals(_env, value, rhs.value); } bool operator < (const Key& rhs) const { return InternalStrictTotalOrder(_env, value, rhs.value); } LispPtr value; private: const LispEnvironment& _env; }; const LispEnvironment& _env; std::map _map; }; inline AssociationClass::AssociationClass(const LispEnvironment& env): _env(env) { } inline const char* AssociationClass::TypeName() const { return "\"Association\""; } inline std::size_t AssociationClass::Size() const { return _map.size(); } inline bool AssociationClass::Contains(LispObject* k) const { return _map.find(Key(_env, k)) != _map.end(); } inline LispObject* AssociationClass::GetElement(LispObject* k) { auto p = _map.find(Key(_env, k)); if (p != _map.end()) return p->second; return nullptr; } inline void AssociationClass::SetElement(LispObject* k, LispObject* v) { _map[Key(_env, LispPtr(k))] = v; } inline bool AssociationClass::DropElement(LispObject* k) { return _map.erase(Key(_env, LispPtr(k))); } #endif /* ASSOCIATIONCLASS_H */ ================================================ FILE: cyacas/libyacas/include/yacas/corefunctions.h ================================================ // // declare the core functions that have special syntax // OPERATOR(bodied,KMaxPrecedence,While) OPERATOR(bodied,KMaxPrecedence,Rule) OPERATOR(bodied,KMaxPrecedence,MacroRule) OPERATOR(bodied,KMaxPrecedence,RulePattern) OPERATOR(bodied,KMaxPrecedence,MacroRulePattern) OPERATOR(bodied,KMaxPrecedence,FromFile) OPERATOR(bodied,KMaxPrecedence,FromString) OPERATOR(bodied,KMaxPrecedence,ToFile) OPERATOR(bodied,KMaxPrecedence,ToString) OPERATOR(bodied,KMaxPrecedence,ToStdout) OPERATOR(bodied,KMaxPrecedence,TraceRule) OPERATOR(bodied,KMaxPrecedence,Subst) OPERATOR(bodied,KMaxPrecedence,LocalSymbols) OPERATOR(bodied,KMaxPrecedence,BackQuote) OPERATOR(prefix,0,`) OPERATOR(prefix,0,@) OPERATOR(prefix,0,_) OPERATOR(infix,0,_) // // Evaluation direction. // CORE_KERNEL_FUNCTION("Hold",LispQuote,1,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Eval",LispEval,1,YacasEvaluator::Function | YacasEvaluator::Fixed) // // Input/output functions // CORE_KERNEL_FUNCTION("Write",LispWrite,1,YacasEvaluator::Function | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("WriteString",LispWriteString,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FullForm",LispFullForm,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DefaultDirectory",LispDefaultDirectory,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FromFile",LispFromFile,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FromString",LispFromString,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Read",LispRead,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("ReadToken",LispReadToken,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("ToFile",LispToFile,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("ToString",LispToString,1,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("ToStdout",LispToStdout,1,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Load",LispLoad,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("TmpFile",LispTmpFile,0,YacasEvaluator::Function | YacasEvaluator::Fixed) // // Symbol protection // CORE_KERNEL_FUNCTION("Protect",LispProtect, 1, YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("UnProtect",LispUnProtect, 1, YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsProtected",LispIsProtected, 1, YacasEvaluator::Macro | YacasEvaluator::Fixed) // // Variable setting/clearing // CORE_KERNEL_FUNCTION("Set",LispSetVar,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MacroSet",LispMacroSetVar,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) // MacroClear is the same as Clear, but with its arguments evaluated first CORE_KERNEL_FUNCTION("Clear",LispClearVar,1,YacasEvaluator::Macro | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("MacroClear",LispClearVar,1,YacasEvaluator::Function | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("Local",LispNewLocal,1,YacasEvaluator::Macro | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("MacroLocal",LispNewLocal,1,YacasEvaluator::Function | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("Variables", LispVars, 0, YacasEvaluator::Function | YacasEvaluator::Fixed) // // List and compound object manipulation // CORE_KERNEL_FUNCTION("Head",LispHead,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathNth",LispNth,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Tail",LispTail,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DestructiveReverse",LispDestructiveReverse,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Length",LispLength,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("List",LispList,1,YacasEvaluator::Macro | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("UnList",LispUnList,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Listify",LispListify,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Concat",LispConcatenate,1,YacasEvaluator::Function | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("ConcatStrings",LispConcatenateStrings,1,YacasEvaluator::Function | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("Delete",LispDelete,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DestructiveDelete",LispDestructiveDelete,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Insert",LispInsert,3,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DestructiveInsert",LispDestructiveInsert,3,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Replace",LispReplace,3,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DestructiveReplace",LispDestructiveReplace,3,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Atom",LispAtomize,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("String",LispStringify,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("CharString",LispCharString,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FlatCopy",LispFlatCopy,1,YacasEvaluator::Function | YacasEvaluator::Fixed) //???CORE_KERNEL_FUNCTION("",LispNoCacheConcatenateStrings) // // Program control flow // CORE_KERNEL_FUNCTION("Prog",LispProgBody,1,YacasEvaluator::Macro | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("While",LispWhile,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("If",LispIf,2,YacasEvaluator::Macro | YacasEvaluator::Variable) // // Error handling // CORE_KERNEL_FUNCTION("Check",LispCheck,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("TrapError",LispTrapError,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("GetCoreError",LispGetCoreError,0,YacasEvaluator::Function | YacasEvaluator::Fixed) // // User function definition // CORE_KERNEL_FUNCTION("Prefix",LispPreFix,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Infix",LispInFix,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Postfix",LispPostFix,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Bodied",LispBodied,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("RuleBase",LispRuleBase,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MacroRuleBase",LispMacroRuleBase,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("RuleBaseListed",LispRuleBaseListed,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MacroRuleBaseListed",LispMacroRuleBaseListed,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DefMacroRuleBase",LispDefMacroRuleBase,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DefMacroRuleBaseListed",LispDefMacroRuleBaseListed,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("HoldArg",LispHoldArg,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Rule",LispNewRule,5,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MacroRule",LispMacroNewRule,5,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("UnFence",LispUnFence,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Retract",LispRetract,2,YacasEvaluator::Function | YacasEvaluator::Fixed) // // Predicates // CORE_KERNEL_FUNCTION("MathNot",LispNot,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION_ALIAS("Not",LispNot,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathAnd",LispLazyAnd,1,YacasEvaluator::Macro | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION_ALIAS("And",LispLazyAnd,1,YacasEvaluator::Macro | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("MathOr",LispLazyOr,1,YacasEvaluator::Macro | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION_ALIAS("Or",LispLazyOr,1,YacasEvaluator::Macro | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("Equals",LispEquals,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION_ALIAS("=",LispEquals,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("LessThan",LispLessThan,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("GreaterThan",LispGreaterThan,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsFunction",LispIsFunction,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsAtom",LispIsAtom,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsNumber",LispIsNumber,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsInteger",LispIsInteger,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsList",LispIsList,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsString",LispIsString,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsBound",LispIsBound,1,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("StrictTotalOrder",LispStrictTotalOrder,2,YacasEvaluator::Function | YacasEvaluator::Fixed) // // Math functions (REQUIRING number inputs);. // CORE_KERNEL_FUNCTION("MathMultiply",LispMultiply,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathAdd",LispAdd,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathSubtract",LispSubtract,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathDivide",LispDivide,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Builtin'Precision'Set",YacasBuiltinPrecisionSet,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathGetExactBits",LispGetExactBits,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathSetExactBits",LispSetExactBits,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathBitCount",LispBitCount,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathSign",LispMathSign,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathIsSmall",LispMathIsSmall,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathNegate",LispMathNegate,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathFloor",LispFloor,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathCeil",LispCeil,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathAbs",LispAbs,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathMod",LispMod,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathDiv",LispDiv,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("BitsToDigits",LispBitsToDigits,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DigitsToBits",LispDigitsToBits,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathGcd",LispGcd,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FastArcSin",LispFastArcSin,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FastLog",LispFastLog,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FastPower",LispFastPower,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("ShiftLeft",LispShiftLeft,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("ShiftRight",LispShiftRight,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FromBase",LispFromBase,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("ToBase",LispToBase,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MaxEvalDepth",LispMaxEvalDepth,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DefLoad",LispDefLoad,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Use",LispUse,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("RightAssociative",LispRightAssociative,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("LeftPrecedence",LispLeftPrecedence,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("RightPrecedence",LispRightPrecedence,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsBodied",LispIsBodied,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsInfix",LispIsInFix,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsPrefix",LispIsPreFix,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("IsPostfix",LispIsPostFix,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("OpPrecedence",LispGetPrecedence,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("OpLeftPrecedence",LispGetLeftPrecedence,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("OpRightPrecedence",LispGetRightPrecedence,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Builtin'Precision'Get",YacasBuiltinPrecisionGet,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("BitAnd",LispBitAnd,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("BitOr",LispBitOr,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("BitXor",LispBitXor,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Secure",LispSecure,1,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FindFile",LispFindFile,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("FindFunction",LispFindFunction,1,YacasEvaluator::Function | YacasEvaluator::Fixed) // Generic object support CORE_KERNEL_FUNCTION("IsGeneric",LispIsGeneric,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("GenericTypeName",LispGenericTypeName,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Array'Create",GenArrayCreate,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Array'Size",GenArraySize,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Array'Get",GenArrayGet,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Array'Set",GenArraySet,3,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Association'Create",GenAssociationCreate,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Association'Size",GenAssociationSize,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Association'Contains",GenAssociationContains,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Association'Get",GenAssociationGet,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Association'Set",GenAssociationSet,3,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Association'Drop",GenAssociationDrop,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Association'Keys",GenAssociationKeys,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Association'ToList",GenAssociationToList,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Association'Head",GenAssociationHead,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("CustomEval",LispCustomEval,4,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("CustomEval'Expression",LispCustomEvalExpression,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("CustomEval'Result",LispCustomEvalResult,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("CustomEval'Locals",LispCustomEvalLocals,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("CustomEval'Stop",LispCustomEvalStop,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("TraceRule",LispTraceRule,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("TraceStack",LispTraceStack,1,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("LispRead",LispReadLisp,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("LispReadListed",LispReadLispListed,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Type",LispType,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("StringMid'Get",YacasStringMidGet,3,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("StringMid'Set",YacasStringMidSet,3,YacasEvaluator::Function | YacasEvaluator::Fixed) // Pattern matching CORE_KERNEL_FUNCTION("Pattern'Create",GenPatternCreate,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Pattern'Matches",GenPatternMatches,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("RuleBaseDefined",LispRuleBaseDefined,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DefLoadFunction",LispDefLoadFunction,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("RuleBaseArgList",LispRuleBaseArgList,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("RulePattern",LispNewRulePattern,5,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MacroRulePattern",LispMacroNewRulePattern,5,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Subst",LispSubst,3,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("LocalSymbols",LispLocalSymbols,1,YacasEvaluator::Macro | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("FastIsPrime",LispFastIsPrime,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("MathFac",LispFac,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("ApplyPure",LispApplyPure,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("PrettyReader'Set",YacasPrettyReaderSet,1,YacasEvaluator::Function | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("PrettyReader'Get",YacasPrettyReaderGet,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("PrettyPrinter'Set",YacasPrettyPrinterSet,1,YacasEvaluator::Function | YacasEvaluator::Variable) CORE_KERNEL_FUNCTION("PrettyPrinter'Get",YacasPrettyPrinterGet,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("GarbageCollect",LispGarbageCollect,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("SetGlobalLazyVariable",LispSetGlobalLazyVariable,2,YacasEvaluator::Macro | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("PatchLoad",LispPatchLoad,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("PatchString",LispPatchString,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DefaultTokenizer",LispDefaultTokenizer,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("XmlTokenizer",LispXmlTokenizer,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("XmlExplodeTag",LispExplodeTag,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Builtin'Assoc",YacasBuiltinAssoc,2,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("CurrentFile",LispCurrentFile,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("CurrentLine",LispCurrentLine,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("`",LispBackQuote,1,YacasEvaluator::Macro | YacasEvaluator::Fixed) // // Operating System services // CORE_KERNEL_FUNCTION("SystemCall", LispSystemCall, 1, YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("SystemName", LispSystemName, 0, YacasEvaluator::Function | YacasEvaluator::Fixed) // // Debugging functions // CORE_KERNEL_FUNCTION("MathDebugInfo",LispDumpBigNumberDebugInfo,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("InDebugMode",LispInDebugMode,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DebugFile",LispDebugFile,1,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("DebugLine",LispDebugLine,1,YacasEvaluator::Function | YacasEvaluator::Fixed) // // Information functions // CORE_KERNEL_FUNCTION("Interpreter",interpreter,0,YacasEvaluator::Function | YacasEvaluator::Fixed) CORE_KERNEL_FUNCTION("Version",LispVersion,0,YacasEvaluator::Function | YacasEvaluator::Fixed) ================================================ FILE: cyacas/libyacas/include/yacas/deffile.h ================================================ /** \file deffile.h deffiles, which speed up loading. * This module adds support for loading files which specify * which script file to look for when trying to use a specific * function. */ #ifndef YACAS_DEFFILE_H #define YACAS_DEFFILE_H #include "yacas/lispstring.h" #include #include /** LispDefFile represents one file that can be loaded just-in-time. */ class LispDefFile { public: LispDefFile(const std::string& aFile); void SetLoaded(); bool IsLoaded() const; const std::string& FileName() const; private: std::string iFileName; bool iIsLoaded; public: std::unordered_set symbols; }; /** LispDefFiles maintains an array of files that can be defloaded. * When the user invokes a DefLoad on a file, an entry is added to the * array of deffiles in the LispEnvironment class. When the function * is called, and there is no body of rules defined for this function, * the engine looks up the correct file to load from this associated * has class. */ class LispDefFiles { public: LispDefFile* File(const std::string& aFileName); private: std::unordered_map _map; }; class LispEnvironment; void LoadDefFile(LispEnvironment& aEnvironment, const std::string& aFileName); inline bool LispDefFile::IsLoaded() const { return iIsLoaded; } inline const std::string& LispDefFile::FileName() const { return iFileName; } #endif ================================================ FILE: cyacas/libyacas/include/yacas/errors.h ================================================ #ifndef YACAS_ERRORS_H #define YACAS_ERRORS_H #include "lispenvironment.h" void CheckArg(bool pred, int arg_idx, LispEnvironment& env, int stack_top); void CheckArgIsString(LispPtr arg, int arg_idx, LispEnvironment& env, int stack_top); void CheckArgIsString(int arg_idx, LispEnvironment& env, int stack_top); void CheckArgIsList(LispPtr arg, int arg_idx, LispEnvironment& env, int stack_top); void CheckArgIsList(int arg_idx, LispEnvironment& env, int stack_top); void CheckNrArgs(int n, LispPtr& aArguments, LispEnvironment& aEnvironment); void ShowStack(LispEnvironment& aEnvironment); void ShowFunctionError(LispPtr& aArguments, LispEnvironment& aEnvironment); void CheckSecure(LispEnvironment& env, int stack_top); #endif ================================================ FILE: cyacas/libyacas/include/yacas/evalfunc.h ================================================ #ifndef YACAS_EVALFUNCBASE_H #define YACAS_EVALFUNCBASE_H // class EvalFuncBase defines the interface to 'something that can // evaluate' class LispEnvironment; class EvalFuncBase { public: virtual void Evaluate(LispPtr& aResult,LispEnvironment& aEnvironment, LispPtr& aArguments) const = 0; virtual ~EvalFuncBase() = default; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/genericobject.h ================================================ #ifndef YACAS_GENERICOBJECT_H #define YACAS_GENERICOBJECT_H /// Abstract class which can be put inside a LispGenericClass. class GenericClass { public: GenericClass() : iReferenceCount(0) {}; virtual ~GenericClass() = default; virtual const char* TypeName() const = 0; public: unsigned iReferenceCount; //TODO: perhaps share the method of reference counting with how it is done in other places }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/infixparser.h ================================================ /** \file infixparser.h * parsing and printing in the infix style. * */ #ifndef YACAS_INFIXPARSER_H #define YACAS_INFIXPARSER_H #include "lispparser.h" #include "lispoperator.h" #include #include class InfixParser final: public LispParser { public: InfixParser(LispTokenizer& aTokenizer, LispInput& aInput, LispEnvironment& aEnvironment, LispOperators& aPrefixOperators, LispOperators& aInfixOperators, LispOperators& aPostfixOperators, LispOperators& aBodiedOperators); void Parse(LispPtr& aResult) override; public: LispOperators& iPrefixOperators; LispOperators& iInfixOperators; LispOperators& iPostfixOperators; LispOperators& iBodiedOperators; private: void ParseCont(LispPtr& aResult); }; class ParsedObject { public: ParsedObject(InfixParser& aParser): iParser(aParser), iEndOfFile(false), iLookAhead(0), iResult(0) { } void Parse(); private: void ReadToken(); void MatchToken(const LispString * aToken); void ReadExpression(int depth); void ReadAtom(); private: void GetOtherSide(int aNrArgsToCombine, int depth); void Combine(int aNrArgsToCombine); void InsertAtom(const LispString* aString); private: void Fail(); // called when parsing fails, raising an exception private: InfixParser& iParser; private: bool iEndOfFile; const LispString* iLookAhead; public: LispPtr iResult; }; class InfixPrinter final: public LispPrinter { public: InfixPrinter(LispOperators& aPrefixOperators, LispOperators& aInfixOperators, LispOperators& aPostfixOperators, LispOperators& aBodiedOperators) : iPrefixOperators(aPrefixOperators), iInfixOperators(aInfixOperators), iPostfixOperators(aPostfixOperators), iBodiedOperators(aBodiedOperators), iPrevLastChar(0),iCurrentEnvironment(nullptr){} void Print( const LispPtr& aExpression, std::ostream& aOutput, LispEnvironment& aEnvironment) override; void RememberLastChar(char aChar) override; private: void Print( const LispPtr& aExpression, std::ostream& aOutput, int iPrecedence); void WriteToken(std::ostream& aOutput, const std::string& aString); private: LispOperators& iPrefixOperators; LispOperators& iInfixOperators; LispOperators& iPostfixOperators; LispOperators& iBodiedOperators; char iPrevLastChar; LispEnvironment* iCurrentEnvironment; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispatom.h ================================================ /** \file lispatom.h * implementation of the standard lisp elements: atom and sublist. * * class LispAtom. This class implements one atom, which is a * reference to a string it represents, and a pointer to the next * lisp atom if it is in a list. * It also has a pointer to the annotation object. * The local class LispPtr implements automatic garbage collection * through reference counting. * * The class LispNumber inherits from LispAtom and holds a numeric atom * in the string representation and in the numeric representation (BigNumber). * The string representation is converted to BigNumber (using the current precision for floats) when a numeric * operation is first requested on the atom. The BigNumber representation is * converted to the string representation whenever the number needs to be printed i.e. LispAtom::String() method is requested. * The string is held in the number (to avoid repeated conversions) and also cached in the string cache (this caching will eventually be abandoned). * When LispNumber is constructed from BigNumber, no string representation is available. * Conversion from string to BigNumber is done only if no BigNumber object is present. */ #ifndef YACAS_LISPATOM_H #define YACAS_LISPATOM_H #include "lispobject.h" #include "lispstring.h" #include "mempool.h" #include "numbers.h" // RefPtr needs definition of BigNumber #include "noncopyable.h" /// This should be used whenever constants 2, 10 mean binary and decimal. // maybe move somewhere else? #ifdef YACAS_NO_CONSTEXPR const int BASE10 = 10; const int BASE2 = 2; #else constexpr int BASE10 = 10; constexpr int BASE2 = 2; #endif class LispEnvironment; class LispAtom: public LispObject, public FastAlloc { public: static LispObject* New(LispEnvironment& aEnvironment, const std::string& aString); const LispString* String() override; LispObject* Copy() const override { return new LispAtom(*this); } private: LispAtom(const LispString* aString); LispStringSmartPtr iString; }; //------------------------------------------------------------------------------ // LispSublist class LispSubList: public LispObject, public FastAlloc { public: static LispSubList* New(LispObject* aSubList); ~LispSubList() override; LispPtr* SubList() override { return &iSubList; } LispObject* Copy() const override { return new LispSubList(*this); } private: // Constructor is private -- use New() instead LispSubList(LispObject* aSubList) : iSubList(aSubList) {} // iSubList's constructor is messed up (it's a LispPtr, duh) public: LispSubList(const LispSubList& other): LispObject(other), iSubList(other.iSubList) {} private: LispPtr iSubList; }; //------------------------------------------------------------------------------ // LispGenericClass class LispGenericClass: public LispObject, public FastAlloc { public: static LispGenericClass* New(GenericClass* aClass); ~LispGenericClass() override; GenericClass* Generic() override; LispObject* Copy() const override { return new LispGenericClass(*this); } private: // Constructor is private -- use New() instead LispGenericClass(GenericClass* aClass); public: LispGenericClass(const LispGenericClass& other) : LispObject(other), iClass(other.iClass) { iClass->iReferenceCount++; } private: LispGenericClass& operator=(const LispGenericClass& other) = delete; private: GenericClass* iClass; }; class LispNumber: public LispObject, public FastAlloc { public: /// constructors: /// construct from another LispNumber LispNumber(BigNumber* aNumber) : iNumber(aNumber), iString(nullptr) {} LispNumber(const LispNumber& other) : LispObject(other), iNumber(other.iNumber), iString(other.iString) {} /// construct from a decimal string representation (also create a number object) and use aBasePrecision decimal digits LispNumber(LispString * aString, int aBasePrecision) : iNumber(nullptr), iString(aString) { Number(aBasePrecision); } LispObject* Copy() const override { return new LispNumber(*this); } /// return a string representation in decimal with maximum decimal precision allowed by the inherent accuracy of the number LispString * String() override; /// give access to the BigNumber object; if necessary, will create a BigNumber object out of the stored string, at given precision (in decimal?) BigNumber* Number(int aPrecision) override; private: /// number object; nullptr if not yet converted from string RefPtr iNumber; /// string representation in decimal; nullptr if not yet converted from BigNumber RefPtr iString; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispenvironment.h ================================================ /** \file lispenvironment.h * General environment access. * */ #ifndef YACAS_LISPENVIRONMENT_H #define YACAS_LISPENVIRONMENT_H #include "lispobject.h" #include "lisphash.h" #include "lispevalhash.h" #include "lispuserfunc.h" #include "deffile.h" #include "lisperror.h" #include "lispio.h" #include "stringio.h" #include "lispglobals.h" #include "lispoperator.h" #include "xmltokenizer.h" #include "errors.h" #include "noncopyable.h" #include #include #include #include #include #include typedef std::unordered_set > LispIdentifiers; class LispDefFiles; class LispInput; class LispOutput; class LispPrinter; class LispUserFunction; class LispMultiUserFunction; class LispEvaluatorBase; class BasicEvaluator; class DefaultDebugger; class LispEnvironment; /// The Lisp environment. /// This huge class is the central class of the Yacas program. It /// implements a dialect of Lisp. class LispEnvironment: NonCopyable { public: /// \name Constructor and destructor //@{ LispEnvironment(YacasCoreCommands &aCoreCommands, LispUserFunctions& aUserFunctions, LispGlobal& aGlobals, LispHashTable& aHashTable, std::ostream& aOutput, LispPrinter& aPrinter, LispOperators &aPreFixOperators, LispOperators &aInFixOperators, LispOperators &aPostFixOperators, LispOperators &aBodiedOperators, LispIdentifiers& protected_symbols, LispInput* aCurrentInput); ~LispEnvironment(); //@} public: /// \name Lisp variables //@{ /// Assign a value to a Lisp variable. /// \param aString name of the variable /// \param aValue value to be assigned to \a aString /// /// If there is a local variable with the name \a aString, the /// object \a aValue is assigned to it. Otherwise, a /// LispGlobalVariable is constructed, and it is associated with /// \a aValue in #iGlobals. /// \sa FindLocal void SetVariable(const LispString* aString, LispPtr& aValue, bool aGlobalLazyVariable); /// Get the value assigned to a variable. /// \param aVariable name of the variable /// \param aResult (on exit) value of \a aVariable /// /// - If there is a local variable with the name \a aString, /// \a aResult is set to point to the value assigned to this local /// variable. /// - If there is a global variable \a aString and its /// #iEvalBeforeReturn is false, its value is returned via /// \a aResult. /// - If there is a global variable \a aString and its /// #iEvalBeforeReturn is true, its value is evaluated. The /// result is assigned back to the variable, its /// #iEvalBeforeReturn is set to false, and a copy of the result /// is returned in \a aResult. /// - Otherwise, \a aResult is set to #nullptr. void GetVariable(const LispString* aVariable, LispPtr& aResult); void UnsetVariable(const LispString * aString); void PushLocalFrame(bool aFenced); void PopLocalFrame(); void NewLocal(const LispString* aVariable, LispObject* aValue); void CurrentLocals(LispPtr& aResult); void GlobalVariables(LispPtr& aResult); //@} public: /// \name Lisp functions //@{ /// Return the #iCoreCommands attribute. const YacasCoreCommands& CoreCommands() const; const LispUserFunctions& UserFunctions() const; /// Add a command to the list of core commands. /// \param aEvaluatorFunc C function evaluating the core command /// \param aString name of the command /// \param aNrArgs number of arguments /// \param aFlags flags, see YacasEvaluator::FunctionFlags void SetCommand(YacasEvalCaller aEvaluatorFunc, const char* aString,int aNrArgs,int aFlags); void RemoveCoreCommand(char* aString); inline LispHashTable& HashTable(); LispUserFunction* UserFunction(LispPtr& aArguments); LispUserFunction* UserFunction(const LispString* aName,int aArity); /// Return LispMultiUserFunction with given name. /// \param aArguments name of the multi user function /// /// The table of user functions, #iUserFunctions, is consulted. If /// a user function with the given name exists, it is returned. /// Otherwise, a new LispMultiUserFunction is constructed, added /// to #iUserFunctions, and returned. LispMultiUserFunction* MultiUserFunction(const LispString* aArguments); LispDefFiles& DefFiles(); void DeclareRuleBase(const LispString* aOperator, LispPtr& aParameters, int aListed); void DeclareMacroRuleBase(const LispString* aOperator, LispPtr& aParameters, int aListed); void DefineRule(const LispString* aOperator,int aArity, int aPrecedence, LispPtr& aPredicate, LispPtr& aBody); void DefineRulePattern(const LispString* aOperator,int aArity, int aPrecedence, LispPtr& aPredicate, LispPtr& aBody); void UnFenceRule(const LispString* aOperator,int aArity); void Retract(const LispString* aOperator,int aArity); void HoldArgument(const LispString* aOperator, const LispString* aVariable); void Protect(const LispString*); void UnProtect(const LispString*); bool Protected(const LispString*) const; //@} public: /// \name Precision //@{ /// set precision to a given number of decimal digits void SetPrecision(int aPrecision); int Precision(void) const; int BinaryPrecision(void) const; //@} public: void SetPrettyPrinter(const LispString* aPrettyPrinter); const LispString* PrettyPrinter(); void SetPrettyReader(const LispString* aPrettyReader); const LispString* PrettyReader(); public: int GetUniqueId(); public: LispPrinter& CurrentPrinter(); public: /// \name Operators //@{ LispOperators& PreFix(); LispOperators& InFix(); LispOperators& PostFix(); LispOperators& Bodied(); //@} public: /// \name Input and output //@{ LispInput* CurrentInput(); void SetCurrentInput(LispInput* aInput); public: std::ostream& CurrentOutput(); void SetCurrentOutput(std::ostream&); //@} protected: /// current precision for user interaction, in decimal and in binary int iPrecision; int iBinaryPrecision; public: std::vector iInputDirectories; //DeletingLispCleanup iCleanup; int iEvalDepth; int iMaxEvalDepth; #ifdef YACAS_NO_ATOMIC_TYPES volatile bool #else std::atomic_bool #endif // YACAS_NO_ATOMIC_TYPES stop_evaluation; LispEvaluatorBase* iEvaluator; public: // Error information when some error occurs. InputStatus iInputStatus; bool secure; public: // pre-found RefPtr iTrue; RefPtr iFalse; RefPtr iEndOfFile; RefPtr iEndStatement; RefPtr iProgOpen; RefPtr iProgClose; RefPtr iNth; RefPtr iBracketOpen; RefPtr iBracketClose; RefPtr iListOpen; RefPtr iListClose; RefPtr iComma; RefPtr iList; RefPtr iProg; int iLastUniqueId; public: // Error reporting std::ostringstream iErrorOutput; DefaultDebugger* iDebugger; private: LispPtr *FindLocal(const LispString * aVariable); struct LispLocalVariable { LispLocalVariable(const LispString* var, LispObject* val): var(var), val(val) { } LispStringSmartPtr var; LispPtr val; }; struct LocalVariableFrame { LocalVariableFrame(std::size_t first, bool fenced): first(first), fenced(fenced) { } std::size_t first; bool fenced; }; std::vector _local_vars; std::vector _local_frames; public: std::ostream* iInitialOutput; private: /// Hash of core commands with associated YacasEvaluator YacasCoreCommands& iCoreCommands; LispUserFunctions& iUserFunctions; LispHashTable& iHashTable; LispDefFiles iDefFiles; LispPrinter& iPrinter; std::ostream* iCurrentOutput; /// Hash of global variables with their values LispGlobal& iGlobals; LispOperators& iPreFixOperators; LispOperators& iInFixOperators; LispOperators& iPostFixOperators; LispOperators& iBodiedOperators; LispIdentifiers& protected_symbols; LispInput* iCurrentInput; const LispString* iPrettyReader; const LispString* iPrettyPrinter; public: LispTokenizer iDefaultTokenizer; XmlTokenizer iXmlTokenizer; LispTokenizer* iCurrentTokenizer; std::deque iStack; }; inline int LispEnvironment::Precision(void) const { return iPrecision; } inline int LispEnvironment::BinaryPrecision(void) const { return iBinaryPrecision; } inline const YacasCoreCommands& LispEnvironment::CoreCommands() const { return iCoreCommands; } inline const LispUserFunctions& LispEnvironment::UserFunctions() const { return iUserFunctions; } inline LispHashTable& LispEnvironment::HashTable() { return iHashTable; } // Local lisp stack, unwindable by the exception handler class LispLocalFrame { public: LispLocalFrame(LispEnvironment& aEnvironment, bool aFenced) : iEnvironment(aEnvironment) { iEnvironment.PushLocalFrame(aFenced); }; virtual ~LispLocalFrame() { iEnvironment.PopLocalFrame(); }; private: LispEnvironment& iEnvironment; }; class LispSecureFrame { public: LispSecureFrame(LispEnvironment& aEnvironment): iEnvironment(aEnvironment), previous_secure(aEnvironment.secure) { iEnvironment.secure = true; }; virtual ~LispSecureFrame() { iEnvironment.secure = previous_secure; }; private: LispEnvironment& iEnvironment; bool previous_secure; }; // LispLocalInput takes ownership over the LispInput class class LispLocalInput: NonCopyable { public: LispLocalInput(LispEnvironment& aEnvironment, LispInput* aInput) : iEnvironment(aEnvironment),iPreviousInput(iEnvironment.CurrentInput()) { iEnvironment.SetCurrentInput(aInput); }; virtual ~LispLocalInput() { iEnvironment.SetCurrentInput(iPreviousInput); }; private: LispEnvironment& iEnvironment; LispInput* iPreviousInput; }; // LispLocalInput takes ownership over the LispInput class class LispLocalOutput: NonCopyable { public: LispLocalOutput(LispEnvironment& aEnvironment, std::ostream& aOutput) : iEnvironment(aEnvironment), iPreviousOutput(&iEnvironment.CurrentOutput()) { iEnvironment.SetCurrentOutput(aOutput); }; virtual ~LispLocalOutput() { iEnvironment.SetCurrentOutput(*iPreviousOutput); }; private: LispEnvironment& iEnvironment; std::ostream* iPreviousOutput; }; class LispLocalEvaluator: NonCopyable { public: LispLocalEvaluator(LispEnvironment& aEnvironment,LispEvaluatorBase* aNewEvaluator); ~LispLocalEvaluator(); private: LispEvaluatorBase* iPreviousEvaluator; LispEnvironment& iEnvironment; }; class LispLocalTrace: NonCopyable { public: LispLocalTrace(LispUserFunction* aUserFunc); ~LispLocalTrace(); private: LispUserFunction* iUserFunc; }; inline void LispEnvironment::SetPrettyReader(const LispString* aPrettyReader) { iPrettyReader = aPrettyReader; } inline const LispString* LispEnvironment::PrettyReader() { return iPrettyReader; } inline void LispEnvironment::SetPrettyPrinter(const LispString * aPrettyPrinter) { iPrettyPrinter = aPrettyPrinter; } inline const LispString* LispEnvironment::PrettyPrinter() { return iPrettyPrinter; } #endif ================================================ FILE: cyacas/libyacas/include/yacas/lisperror.h ================================================ #ifndef YACAS_LISPERROR_H #define YACAS_LISPERROR_H #include class LispError { public: LispError(const std::string& msg); const char* what() const; private: const std::string _what; }; inline LispError::LispError(const std::string& what): _what(what) { } inline const char* LispError::what() const { return _what.c_str(); } class LispErrInvalidArg: public LispError { public: LispErrInvalidArg(): LispError("Invalid argument") {} }; class LispErrWrongNumberOfArgs: public LispError { public: LispErrWrongNumberOfArgs(): LispError("Wrong number of arguments") {} }; class LispErrNotList: public LispError { public: LispErrNotList(): LispError("Argument is not a list") {} }; class LispErrListNotLongEnough: public LispError { public: LispErrListNotLongEnough(): LispError("List not long enough") {} }; class LispErrInvalidStack: public LispError { public: LispErrInvalidStack(): LispError("Invalid stack") {} }; class Quitting: public LispError { public: Quitting(): LispError("Quitting...") {} }; class LispErrNotEnoughMemory: public LispError { public: LispErrNotEnoughMemory(): LispError("Not enough memory") {} }; class InvalidToken: public LispError { public: InvalidToken(): LispError("Empty token during parsing") {} }; class LispErrInvalidExpression: public LispError { public: LispErrInvalidExpression(): LispError("Error parsing expression") {} explicit LispErrInvalidExpression(const std::string& ctx): LispError("Error parsing expression near token " + ctx) {} }; class LispErrUnprintableToken: public LispError { public: LispErrUnprintableToken(): LispError("Unprintable atom") {} }; class LispErrFileNotFound: public LispError { public: LispErrFileNotFound(): LispError("File not found") {} }; class LispErrReadingFile: public LispError { public: LispErrReadingFile(): LispError("Error reading file") {} }; class LispErrCreatingUserFunction: public LispError { public: LispErrCreatingUserFunction(): LispError("Could not create user function") {} }; class LispErrCreatingRule: public LispError { public: LispErrCreatingRule(): LispError("Could not create rule") {} }; class LispErrArityAlreadyDefined: public LispError { public: LispErrArityAlreadyDefined(): LispError("Rule base with this arity already defined") {} }; class LispErrCommentToEndOfFile: public LispError { public: LispErrCommentToEndOfFile(): LispError("Reaching end of file within a comment block") {} }; class LispErrNotString: public LispError { public: LispErrNotString(): LispError("Argument is not a string") {} }; class LispErrNotInteger: public LispError { public: LispErrNotInteger(): LispError("Argument is not an integer") {} }; class LispErrParsingInput: public LispError { public: LispErrParsingInput(): LispError("Error while parsing input") {} }; class LispErrMaxRecurseDepthReached: public LispError { public: LispErrMaxRecurseDepthReached(): LispError("Max evaluation stack depth reached.\nPlease use MaxEvalDepth to increase the stack size as needed.") {} }; class LispErrDefFileAlreadyChosen: public LispError { public: LispErrDefFileAlreadyChosen(): LispError("DefFile already chosen for function") {} }; class LispErrDivideByZero: public LispError { public: LispErrDivideByZero(): LispError("Divide by zero") {} }; class LispErrNotAnInFixOperator: public LispError { public: LispErrNotAnInFixOperator(): LispError("Trying to make a non-infix operator right-associative") {} }; class LispErrUser: public LispError { public: LispErrUser(const std::string& msg): LispError(msg) {} }; class LispErrIsNotInFix: public LispError { public: LispErrIsNotInFix(): LispError("Trying to get precedence of non-infix operator") {} }; class LispErrSecurityBreach: public LispError { public: LispErrSecurityBreach(): LispError("Trying to perform an insecure action") {} }; class LispErrLibraryNotFound: public LispError { public: LispErrLibraryNotFound(): LispError("Could not find library") {} }; class LispErrUserInterrupt: public LispError { public: LispErrUserInterrupt(): LispError("User interrupted calculation") {} }; class LispErrNonBooleanPredicateInPattern: public LispError { public: LispErrNonBooleanPredicateInPattern(): LispError("Predicate doesn't evaluate to a boolean in pattern") {} }; class LispErrProtectedSymbol: public LispError { public: explicit LispErrProtectedSymbol(const std::string& s): LispError(std::string("Attempt to override protected symbol: ") + s) {} }; class LispErrGeneric: public LispError { public: LispErrGeneric(const std::string& what): LispError(what) {} }; class LispEnvironment; class LispOutput; void HandleError(const LispError&, LispEnvironment& aEnvironment, std::ostream& aOutput); #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispeval.h ================================================ /** \file lispeval.h * Evaluation of expressions. * */ #ifndef YACAS_LISPEVAL_H #define YACAS_LISPEVAL_H #include "lispobject.h" #include "lispenvironment.h" class UserStackInformation { public: UserStackInformation() : iOperator(),iExpression(),iRulePrecedence(-1),iSide(0) { } LispPtr iOperator; LispPtr iExpression; int iRulePrecedence; int iSide; // 0=pattern, 1=body }; /// Abstract evaluator for Lisp expressions. /// Eval() is a pure virtual function, to be provided by the derived class. /// The other functions are stubs. class LispEvaluatorBase { public: LispEvaluatorBase() : iBasicInfo() {} virtual ~LispEvaluatorBase() = default; virtual void Eval(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression)=0; virtual void ResetStack(); virtual UserStackInformation& StackInformation(); virtual void ShowStack(LispEnvironment& aEnvironment, std::ostream& aOutput); private: UserStackInformation iBasicInfo; }; /// The basic evaluator for Lisp expressions. class BasicEvaluator : public LispEvaluatorBase { public: /// Evaluate a Lisp expression /// \param aEnvironment the Lisp environment, in which the /// evaluation should take place. /// \param aResult the result of the evaluation. /// \param aExpression the expression to evaluate. /// /// First, the evaluation depth is checked. An error is raised if /// the maximum evaluation depth is exceeded. /// /// The next step is the actual evaluation. \a aExpression is a /// LispObject, so we can distinguish three cases. /// - If \a aExpression is a string starting with \c " , it is /// simply copied in \a aResult. If it starts with another /// character (this includes the case where it represents a /// number), the environment is checked to see whether a /// variable with this name exists. If it does, its value is /// copied in \a aResult, otherwise \a aExpression is copied. /// - If \a aExpression is a list, the head of the list is /// examined. If the head is not a string. InternalApplyPure() /// is called. If the head is a string, it is checked against /// the core commands; if there is a check, the corresponding /// evaluator is called. Then it is checked agaist the list of /// user function with GetUserFunction() . Again, the /// corresponding evaluator is called if there is a check. If /// all fails, ReturnUnEvaluated() is called. /// - Otherwise (ie. if \a aExpression is a generic object), it is /// copied in \a aResult. /// /// \note The result of this operation must be a unique (copied) /// element! Eg. its Next might be set... /// /// The LispPtr it can be stored in to is passed in as argument, so it /// does not need to be constructed by the calling environment. void Eval(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) override; }; class TracedEvaluator : public BasicEvaluator { public: void Eval(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) override; protected: std::ostringstream errorOutput; }; class TracedStackEvaluator final: public BasicEvaluator { public: TracedStackEvaluator() : objs() {} ~TracedStackEvaluator() override; void Eval(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) override; void ResetStack() override; UserStackInformation& StackInformation() override; void ShowStack(LispEnvironment& aEnvironment, std::ostream& aOutput) override; private: void PushFrame(); void PopFrame(); private: std::vector objs; }; /* GetUserFunction : get user function, possibly loading the required files to read in the function definition */ LispUserFunction* GetUserFunction(LispEnvironment& aEnvironment, LispPtr* subList); /* Tracing functions */ void TraceShowEnter(LispEnvironment& aEnvironment, LispPtr& aExpression); void TraceShowLeave(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression); void TraceShowArg(LispEnvironment& aEnvironment,LispPtr& aParam, LispPtr& aValue); void ShowExpression(LispString& outString, LispEnvironment& aEnvironment, LispPtr& aExpression); class YacasDebuggerBase { public: virtual ~YacasDebuggerBase() = default; virtual void Start() = 0; virtual void Finish() = 0; virtual void Enter(LispEnvironment& aEnvironment, LispPtr& aExpression) = 0; virtual void Leave(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) = 0; virtual void Error(LispEnvironment& aEnvironment) = 0; virtual bool Stopped() = 0; }; class DefaultDebugger final: public YacasDebuggerBase { public: DefaultDebugger(LispPtr& aEnter, LispPtr& aLeave, LispPtr& aError) : iEnter(aEnter), iLeave(aLeave), iError(aError), iTopExpr(),iTopResult(),iStopped(false),defaultEval() {}; void Start() override; void Finish() override; void Enter(LispEnvironment& aEnvironment, LispPtr& aExpression) override; void Leave(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) override; void Error(LispEnvironment& aEnvironment) override; bool Stopped() override; LispPtr iEnter; LispPtr iLeave; LispPtr iError; LispPtr iTopExpr; LispPtr iTopResult; bool iStopped; protected: BasicEvaluator defaultEval; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispevalhash.h ================================================ /** \file lispevalhash.h * Storage of executable commands * */ #ifndef YACAS_LISPEVALHASH_H #define YACAS_LISPEVALHASH_H #include "lispobject.h" #include "evalfunc.h" #include // new-style evaluator, passing arguments onto the stack in LispEnvironment typedef void (*YacasEvalCaller)(LispEnvironment& aEnvironment,int aStackTop); class YacasEvaluator: public EvalFuncBase { public: // FunctionFlags can be orred when passed to the constructor of this function enum FunctionFlags { Function=0, // Function: evaluate arguments Macro=1, // Function: don't evaluate arguments Fixed = 0, // fixed number of arguments Variable = 2 // variable number of arguments }; YacasEvaluator(YacasEvalCaller aCaller,int aNrArgs, int aFlags) : iCaller(aCaller), iNrArgs(aNrArgs), iFlags(aFlags) { } void Evaluate(LispPtr& aResult, LispEnvironment& aEnvironment, LispPtr& aArguments) const override; private: YacasEvalCaller iCaller; int iNrArgs; int iFlags; }; typedef std::unordered_map > YacasCoreCommands; #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispglobals.h ================================================ /** \file lispglobals.h * Storage of globals in a associated hash * */ #ifndef YACAS_LISPGLOBALS_H #define YACAS_LISPGLOBALS_H #include "lispobject.h" #include "lisphash.h" /// Value of a Lisp global variable. /// The only special feature of this class is the attribute /// #iEvalBeforeReturn, which defaults to #false. If this /// attribute is set to #true, the value in #iValue needs to be /// evaluated to get the value of the Lisp variable. /// \sa LispEnvironment::GetVariable() class LispGlobalVariable { public: LispGlobalVariable(const LispGlobalVariable& aOther); LispGlobalVariable(LispPtr& aValue): iValue(aValue), iEvalBeforeReturn(false) {} LispGlobalVariable& operator=(const LispGlobalVariable& aOther); void SetEvalBeforeReturn(bool aEval); LispPtr iValue; bool iEvalBeforeReturn; }; typedef std::unordered_map > LispGlobal; inline LispGlobalVariable::LispGlobalVariable(const LispGlobalVariable& aOther): iValue(aOther.iValue), iEvalBeforeReturn(false) { } inline void LispGlobalVariable::SetEvalBeforeReturn(bool aEval) { iEvalBeforeReturn = aEval; } inline LispGlobalVariable& LispGlobalVariable::operator=(const LispGlobalVariable& aOther) { iValue = aOther.iValue; return *this; } #endif ================================================ FILE: cyacas/libyacas/include/yacas/lisphash.h ================================================ /** \file lisphash.h * hashing of strings. Each string will exist only once in the * hash table, and have an unique id. */ #ifndef YACAS_LISPHASH_H #define YACAS_LISPHASH_H #include "lispstring.h" #include /** * This is the symbol table, implemented as a hash table for fast * lookup. It is meant to store any string just once, have fast * searching for strings and return a reference to the string. * This also allows fast comparison of two strings (two strings * are equal iff the pointers to the strings are equal). */ class LispHashTable { public: // If string not yet in table, insert. Afterwards return the string. const LispString* LookUp(const std::string&); void GarbageCollect(); private: std::unordered_map _rep; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispio.h ================================================ /** \file lispio.h * definitions of pure input output classes. */ #ifndef YACAS_LISPIO_H #define YACAS_LISPIO_H #include #include class InputStatus { public: InputStatus() : iFileName("none") , iLineNumber(-1) {} void SetTo(const std::string& aFileName); void RestoreFrom(InputStatus& aPreviousStatus); int LineNumber() const; const std::string& FileName() const; void NextLine(); private: std::string iFileName; int iLineNumber; }; inline int InputStatus::LineNumber() const { return iLineNumber; } inline const std::string& InputStatus::FileName() const { return iFileName; } inline void InputStatus::NextLine() { iLineNumber++; } /** \class LispInput : pure abstract class declaring the interface * that needs to be implemented by a file (something that expressions * can be read from). */ class LispInput { public: /** Constructor with InputStatus. InputStatus retains the information * needed when an error occurred, and the file has already been * closed. */ LispInput(InputStatus& aStatus) : iStatus(aStatus) {}; virtual ~LispInput() = default; /// Return the next character in the file virtual char32_t Next() = 0; /** Peek at the next character in the file, without advancing the file * pointer. */ virtual char32_t Peek() = 0; virtual const InputStatus& Status() const {return iStatus;}; /// Check if the file position is past the end of the file. virtual bool EndOfStream() const = 0; virtual std::size_t Position() const = 0; virtual void SetPosition(std::size_t aPosition) = 0; protected: InputStatus& iStatus; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispobject.h ================================================ /** \file lispobject.h * Implementation of basic LispObject, which is the base class for * anything that can be put in a linked list. * * class LispObject. This class implements one lisp object, which is a * abstract class containing reference counting and a next pointer. * derive from this to implement specific types of list elements. * The local class LispPtr implements automatic garbage collection * through reference counting. * */ #ifndef YACAS_LISPOBJECT_H #define YACAS_LISPOBJECT_H #include "refcount.h" #include "lispstring.h" #include "genericobject.h" #include "noncopyable.h" class LispObject; class BigNumber; /** class LispPtr. A LispPtr is a smart pointer to a LispObject. * It does the reference counting, and consequent destruction if needed. * LispPtr is used in LispObject as a pointer to the next object; and * LispPtr::GoNext() advances one step in this LispObject::Nixed() chain. * Diverse built-in functions use LispPtr to hold temporary values. */ typedef RefPtr LispPtr; /** class LispObject is the base object class that can be put in * linked lists. It either has a pointer to a string, obtained through * String(), or it is a holder for a sublist, obtainable through SubList(), * or it is a generic object, in which case Generic() returns non-nullptr. * Only one of these three functions should return a non-nullptr value. * It is a reference-counted object. LispPtr handles the reference counting. */ class LispObject: public RefCount { public: inline LispPtr& Nixed(); public: //Derivables virtual ~LispObject() = default; /** Return string representation, or nullptr if the object doesn't have one. * the string representation is only relevant if the object is a * simple atom. This method returns nullptr by default. */ virtual const LispString* String() { return nullptr; } /** If this object is a list, return a pointer to it. * Default behaviour is to return nullptr. */ virtual LispPtr* SubList() { return nullptr; } virtual GenericClass* Generic() { return nullptr; } /** If this is a number, return a BigNumber representation */ virtual BigNumber* Number([[maybe_unused]] int aPrecision) { return nullptr; } virtual LispObject* Copy() const = 0; public: int Equal(LispObject& aOther); inline int operator==(LispObject& aOther); inline int operator!=(LispObject& aOther); protected: inline LispObject() : iNext() { } inline LispObject([[maybe_unused]] const LispObject& other) : RefCount(), iNext() { } inline LispObject& operator=([[maybe_unused]] const LispObject& other) { return *this; } private: LispPtr iNext; }; /** * class LispIterator works almost like LispPtr, but doesn't enforce * reference counting, so it should be faster. Use LispIterator * (instead of LispPtr) to traverse a lisp expression non-destructively. */ class LispIterator { public: // ala TEMPLATE CLASS iterator //typedef forward_iterator_tag iterator_category; typedef LispPtr value_type; typedef int /*ptrdiff_t*/ difference_type; typedef LispPtr* pointer; typedef LispPtr& reference; public: LispIterator() : _Ptr(0) {} // construct with null node pointer LispIterator(pointer ptr) : _Ptr(ptr) {} // construct with node pointer /*non-standard*/ LispIterator(reference ref) : _Ptr(&ref) {} // construct with node reference reference operator*() const { return (*(_Ptr)); } // return designated value pointer operator->() const { return (_Ptr); } // return pointer to class object inline LispIterator& operator++() // preincrement { //precondition: _Ptr != nullptr assert(_Ptr != nullptr); //expand: _Ptr = _Nextnode(_Ptr); LispObject * pObj = _Ptr->operator->(); _Ptr = pObj ? &(pObj->Nixed()) : nullptr; return (*this); } LispIterator operator++(int) { LispIterator _Tmp = *this; ++*this; return (_Tmp); } // postincrement bool operator==(const LispIterator& other) const { return (_Ptr == other._Ptr); } // test for iterator equality bool operator!=(const LispIterator& other) const { return (!(*this == other)); } // test for iterator inequality // The following operators are not used yet, and would need to be tested before used. //LispIterator& operator--() { _Ptr = _Prevnode(_Ptr); return (*this); } // predecrement //LispIterator operator--(int) { LispIterator _Tmp = *this; --*this; return (_Tmp); } // postdecrement protected: pointer _Ptr; // pointer to node public: inline LispObject* getObj() const { return (*_Ptr).operator->(); } }; class LispConstIterator { public: // ala TEMPLATE CLASS iterator //typedef forward_iterator_tag iterator_category; typedef const LispPtr value_type; typedef int /*ptrdiff_t*/ difference_type; typedef const LispPtr* pointer; typedef const LispPtr& reference; public: LispConstIterator() : _Ptr(0) {} // construct with null node pointer LispConstIterator(pointer ptr) : _Ptr(ptr) {} // construct with node pointer /*non-standard*/ LispConstIterator(reference ref) : _Ptr(&ref) {} // construct with node reference reference operator*() const { return (*(_Ptr)); } // return designated value pointer operator->() const { return (_Ptr); } // return pointer to class object inline LispConstIterator& operator++() // preincrement { //precondition: _Ptr != nullptr assert(_Ptr != nullptr); //expand: _Ptr = _Nextnode(_Ptr); LispObject * pObj = _Ptr->operator->(); _Ptr = pObj ? &(pObj->Nixed()) : nullptr; return (*this); } LispConstIterator operator++(int) { LispConstIterator _Tmp = *this; ++*this; return (_Tmp); } // postincrement bool operator==(const LispConstIterator& other) const { return (_Ptr == other._Ptr); } // test for iterator equality bool operator!=(const LispConstIterator& other) const { return (!(*this == other)); } // test for iterator inequality // The following operators are not used yet, and would need to be tested before used. //LispConstIterator& operator--() { _Ptr = _Prevnode(_Ptr); return (*this); } // predecrement //LispConstIterator operator--(int) { LispConstIterator _Tmp = *this; --*this; return (_Tmp); } // postdecrement protected: pointer _Ptr; // pointer to node public: inline const LispObject* getObj() const { return (*_Ptr).operator->(); } }; inline LispPtr& LispObject::Nixed() { return iNext; } inline int LispObject::operator==(LispObject& aOther) { return Equal(aOther); } inline int LispObject::operator!=(LispObject& aOther) { return !Equal(aOther); } #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispoperator.h ================================================ /* * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesset General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ /* * File: lispoperator.h * Author: mazur * * Created on February 12, 2016, 3:05 PM */ #ifndef LISPOPERATOR_H #define LISPOPERATOR_H #include #ifdef YACAS_NO_CONSTEXPR const int KMaxPrecedence = 60000; #else constexpr int KMaxPrecedence = 60000; #endif class LispInFixOperator { public: explicit #ifndef YACAS_NO_CONSTEXPR constexpr #endif LispInFixOperator(int aPrecedence = KMaxPrecedence): iPrecedence(aPrecedence), iLeftPrecedence(aPrecedence), iRightPrecedence(aPrecedence), iRightAssociative(false) {} void SetRightAssociative() { iRightAssociative = true; } void SetLeftPrecedence(int aPrecedence) { iLeftPrecedence = aPrecedence; } void SetRightPrecedence(int aPrecedence) { iRightPrecedence = aPrecedence; } int iPrecedence; int iLeftPrecedence; int iRightPrecedence; bool iRightAssociative; }; typedef std::unordered_map > LispOperators; #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispparser.h ================================================ /** \file lispparser.h * parsing and printing in the old-fashioned lisp style * */ #ifndef YACAS_LISPPARSER_H #define YACAS_LISPPARSER_H #include "lispobject.h" #include "tokenizer.h" #include "lispio.h" #include "evalfunc.h" #include class LispParser { public: LispParser(LispTokenizer& aTokenizer, LispInput& aInput, LispEnvironment& aEnvironment); virtual void Parse(LispPtr& aResult ); protected: void ParseList(LispPtr& aResult); void ParseAtom(LispPtr& aResult, const LispString* aToken); public: LispTokenizer& iTokenizer; LispInput& iInput; LispEnvironment& iEnvironment; int iListed; }; class LispPrinter { public: virtual void Print( const LispPtr& aExpression, std::ostream& aOutput, LispEnvironment& aEnvironment); virtual void RememberLastChar(char aChar); private: void PrintExpression( const LispPtr& aExpression, std::ostream& aOutput, LispEnvironment& aEnvironment, int aDepth=0); void Indent(std::ostream& aOutput, int aDepth); }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispstring.h ================================================ /** \file lispstring.h * Defining a string class. */ #ifndef YACAS_LISPSTRING_H #define YACAS_LISPSTRING_H #include "refcount.h" #include /** \class LispString : zero-terminated byte-counted string. * Also keeps a reference count for any one interested. */ class LispString: public RefCount, public std::string { public: explicit LispString(const std::string& = ""); }; inline LispString::LispString(const std::string& s): std::string(s) { } typedef RefPtr LispStringSmartPtr; #endif ================================================ FILE: cyacas/libyacas/include/yacas/lispuserfunc.h ================================================ #ifndef YACAS_LISPUSERFUNC_H #define YACAS_LISPUSERFUNC_H #include "lispobject.h" #include "evalfunc.h" #include #include class LispEnvironment; /// Abstract class providing the basic user function API. /// Instances of this class are associated to the name of the function /// via an associated hash table. When obtained, they can be used to /// evaluate the function with some arguments. class LispUserFunction : public EvalFuncBase { public: LispUserFunction() : iFenced(true),iTraced(false) {}; virtual void HoldArgument(const LispString* aVariable) = 0; virtual void DeclareRule(int aPrecedence, LispPtr& aPredicate, LispPtr& aBody) = 0; virtual void DeclareRule(int aPrecedence, LispPtr& aBody) = 0; virtual void DeclarePattern(int aPrecedence, LispPtr& aPredicate, LispPtr& aBody) = 0; virtual const LispPtr& ArgList() const = 0; public: //unfencing inline void UnFence() {iFenced = false;}; inline bool Fenced() const {return iFenced;}; public: //tracing inline void Trace() {iTraced = true;}; inline void UnTrace() {iTraced = false;}; inline bool Traced() const {return iTraced;}; private: bool iFenced; bool iTraced; }; /// User function with a specific arity. /// This is still an abstract class, but the arity (number of /// arguments) of the function is now fixed. class LispArityUserFunction : public LispUserFunction { public: virtual unsigned Arity() const = 0; virtual bool IsArity(unsigned aArity) const = 0; }; class LispDefFile; /// Set of LispArityUserFunction's. /// By using this class, you can associate multiple functions (with /// different arities) to one name. A specific LispArityUserFunction /// can be selected by providing its name. Additionally, the name of /// the file in which the function is defined, can be specified. class LispMultiUserFunction final { public: /// Constructor. LispMultiUserFunction() : iFunctions(),iFileToOpen(nullptr) {}; /** When adding a multi-user function to the association hash table, the copy constructor is used. * We should at least make sure that iFunctions is empty, so there is no copying needed (for efficiency). * Casually having a copy-constructor on CDeletingArrayGrower should be avoided, to make sure it is * not used accidentally. */ inline LispMultiUserFunction([[maybe_unused]] const LispMultiUserFunction& aOther) : iFunctions(), iFileToOpen(nullptr) { assert(aOther.iFileToOpen == 0); assert(aOther.iFunctions.size() == 0); } inline LispMultiUserFunction& operator=([[maybe_unused]] const LispMultiUserFunction& aOther) { // copy constructor not written yet, hence the assert assert(aOther.iFileToOpen == 0); assert(aOther.iFunctions.size() == 0); assert(iFileToOpen == 0); assert(iFunctions.size() == 0); return *this; } /// Return user function with given arity. LispUserFunction* UserFunc(int aArity); /// Destructor. virtual ~LispMultiUserFunction(); /// Specify that some argument should be held. virtual void HoldArgument(const LispString* aVariable); /// Add another LispArityUserFunction to #iFunctions. virtual void DefineRuleBase(LispArityUserFunction* aNewFunction); /// Delete tuser function with given arity. virtual void DeleteBase(int aArity); private: /// Set of LispArityUserFunction's provided by this LispMultiUserFunction. std::vector iFunctions; public: /// File to read for the definition of this function. LispDefFile* iFileToOpen; }; /// Associated hash of LispMultiUserFunction objects. typedef std::unordered_map > LispUserFunctions; #endif ================================================ FILE: cyacas/libyacas/include/yacas/mathcommands.h ================================================ #ifndef YACAS_MATHCOMMANDS_H #define YACAS_MATHCOMMANDS_H #include "lispenvironment.h" #include "lispevalhash.h" #include "lispobject.h" #include "lispglobals.h" //#define CORE_FUNCTION(NAME) void NAME(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aArguments); #define CORE_KERNEL_FUNCTION(iname,fname,nrargs,flags) void fname(LispEnvironment& aEnvironment, int aStackTop); #define CORE_KERNEL_FUNCTION_ALIAS(iname,fname,nrargs,flags) int JimDummyFunction(); #define OPERATOR(kind, prec, yacas_name) int JimDummyFunction(); #include "corefunctions.h" #undef CORE_KERNEL_FUNCTION #undef CORE_KERNEL_FUNCTION_ALIAS #undef OPERATOR #endif ================================================ FILE: cyacas/libyacas/include/yacas/mathuserfunc.h ================================================ #ifndef YACAS_MATHUSERFUNC_H #define YACAS_MATHUSERFUNC_H #include "lispuserfunc.h" #include "patternclass.h" #include "noncopyable.h" #include /// A mathematical function defined by several rules. /// This is the basic class which implements functions in Yacas. /// Evaluation is done by consulting a set of rewriting rules. The /// body of the first rule that matches, is evaluated and this gives /// the result of evaluating the function. class BranchingUserFunction : public LispArityUserFunction { public: /// Structure containing name of parameter and whether it is put on hold. class BranchParameter { public: BranchParameter(const LispString* aParameter = nullptr, int aHold=false) : iParameter(aParameter), iHold(aHold) {} const LispString* iParameter; int iHold; }; /// Abstract base class for rules. class BranchRuleBase { public: virtual ~BranchRuleBase() = default; virtual bool Matches(LispEnvironment& aEnvironment, LispPtr* aArguments) = 0; virtual int Precedence() const = 0; virtual LispPtr& Body() = 0; }; /// A rule with a predicate. /// This rule matches if the predicate evaluates to #true. class BranchRule : public BranchRuleBase { public: BranchRule(int aPrecedence,LispPtr& aPredicate,LispPtr& aBody) : iPrecedence(aPrecedence),iBody(aBody),iPredicate(aPredicate) { } /// Return true if the rule matches. /// #iPredicate is evaluated in \a Environment. If the result /// IsTrue(), this function returns true. bool Matches(LispEnvironment& aEnvironment, LispPtr* aArguments); /// Access #iPrecedence. int Precedence() const; /// Access #iBody. LispPtr& Body(); protected: BranchRule() : iPrecedence(0),iBody(),iPredicate() {}; protected: int iPrecedence; LispPtr iBody; LispPtr iPredicate; }; /// A rule that always matches. class BranchRuleTruePredicate : public BranchRule { public: BranchRuleTruePredicate(int aPrecedence,LispPtr& aBody) { iPrecedence = aPrecedence; iBody = (aBody); } /// Return #true, always. bool Matches(LispEnvironment& aEnvironment, LispPtr* aArguments); }; /// A rule which matches if the corresponding PatternClass matches. class BranchPattern : public BranchRuleBase, NonCopyable { public: /// Constructor. /// \param aPrecedence precedence of the rule /// \param aPredicate generic object of type \c Pattern /// \param aBody body of the rule BranchPattern(int aPrecedence,LispPtr& aPredicate,LispPtr& aBody) : iPrecedence(aPrecedence),iBody(aBody),iPredicate(aPredicate),iPatternClass(nullptr) { GenericClass *gen = aPredicate->Generic(); PatternClass* pat = dynamic_cast(gen); if (!pat) throw LispErrInvalidArg(); iPatternClass = pat; } /// Return true if the corresponding pattern matches. bool Matches(LispEnvironment& aEnvironment, LispPtr* aArguments); /// Access #iPrecedence int Precedence() const; /// Access #iBody LispPtr& Body(); protected: /// The precedence of this rule. int iPrecedence; /// The body of this rule. LispPtr iBody; /// Generic object of type \c Pattern containing #iPatternClass LispPtr iPredicate; /// The pattern that decides whether this rule matches. PatternClass *iPatternClass; }; /// Constructor. /// \param aParameters linked list constaining the names of the arguments /// /// #iParamList and #iParameters are set from \a aParameters. BranchingUserFunction(LispPtr& aParameters); /// Destructor. ~BranchingUserFunction(); /// Evaluate the function on given arguments. /// \param aResult (on output) the result of the evaluation /// \param aEnvironment the underlying Lisp environment /// \param aArguments the arguments to the function /// /// First, all arguments are evaluated by the evaluator associated /// to \a aEnvironment, unless the \c iHold flag of the /// corresponding parameter is true. Then a new LispLocalFrame is /// constructed, in which the actual arguments are assigned to the /// names of the formal arguments, as stored in \c iParameter. Then /// all rules in #iRules are tried one by one. The body of the /// first rule that matches is evaluated, and the result is put in /// \a aResult. If no rule matches, \a aResult will recieve a new /// expression with evaluated arguments. void Evaluate(LispPtr& aResult,LispEnvironment& aEnvironment, LispPtr& aArguments) const override; /// Put an argument on hold. /// \param aVariable name of argument to put un hold /// /// The \c iHold flag of the corresponding argument is set. This /// implies that this argument is not evaluated by Evaluate(). void HoldArgument(const LispString* aVariable) override; /// Return true if the arity of the function equals \a aArity. bool IsArity(unsigned aArity) const override; /// Return the arity (number of arguments) of the function. unsigned Arity() const override; /// Add a BranchRule to the list of rules. /// \sa InsertRule() void DeclareRule(int aPrecedence, LispPtr& aPredicate, LispPtr& aBody) override; /// Add a BranchRuleTruePredicate to the list of rules. /// \sa InsertRule() void DeclareRule(int aPrecedence, LispPtr& aBody) override; /// Add a BranchPattern to the list of rules. /// \sa InsertRule() void DeclarePattern(int aPrecedence, LispPtr& aPredicate, LispPtr& aBody) override; /// Insert any BranchRuleBase object in the list of rules. /// This function does the real work for DeclareRule() and /// DeclarePattern(): it inserts the rule in #iRules, while /// keeping it sorted. The algorithm is \f$O(\log n)\f$, where /// \f$n\f$ denotes the number of rules. void InsertRule(int aPrecedence,BranchRuleBase* newRule); /// Return the argument list, stored in #iParamList const LispPtr& ArgList() const override; protected: /// List of arguments, with corresponding \c iHold property. std::vector iParameters; /// List of rules, sorted on precedence. std::vector iRules; /// List of arguments LispPtr iParamList; }; class ListedBranchingUserFunction final: public BranchingUserFunction { public: ListedBranchingUserFunction(LispPtr& aParameters); bool IsArity(unsigned aArity) const override; void Evaluate(LispPtr& aResult,LispEnvironment& aEnvironment, LispPtr& aArguments) const override; }; class MacroUserFunction : public BranchingUserFunction { public: MacroUserFunction(LispPtr& aParameters); void Evaluate(LispPtr& aResult,LispEnvironment& aEnvironment, LispPtr& aArguments) const override; }; class ListedMacroUserFunction final: public MacroUserFunction { public: ListedMacroUserFunction(LispPtr& aParameters); bool IsArity(unsigned aArity) const override; void Evaluate(LispPtr& aResult,LispEnvironment& aEnvironment, LispPtr& aArguments) const override; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/mempool.h ================================================ #ifndef YACAS_MEMPOOL_H #define YACAS_MEMPOOL_H #include "noncopyable.h" #include #include class MemPool: NonCopyable { public: explicit MemPool(unsigned block_size, unsigned no_blocks); ~MemPool() noexcept; void* alloc(); void free(void *p) noexcept; private: unsigned _block_size; unsigned _no_blocks; unsigned _no_free_blocks; unsigned _no_initialized_blocks; std::uint8_t* _pool; std::uint8_t* _next_free_block; MemPool* _next_pool; }; template class FastAlloc { public: static void* operator new(std::size_t) { return _pool.alloc(); } static void operator delete(void* p) { _pool.free(p); } private: static MemPool _pool; }; template MemPool FastAlloc::_pool(sizeof (T), 32768); #endif ================================================ FILE: cyacas/libyacas/include/yacas/noncopyable.h ================================================ #ifndef YACAS_NONCOPYABLE_H #define YACAS_NONCOPYABLE_H class NonCopyable { protected: #ifndef YACAS_NO_CONSTEXPR constexpr #endif NonCopyable() = default; ~NonCopyable() = default; private: NonCopyable(const NonCopyable&) = delete; NonCopyable& operator=(const NonCopyable&) = delete; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/numbers.h ================================================ #ifndef YACAS_NUMBERS_H #define YACAS_NUMBERS_H #include "lispenvironment.h" #include "anumber.h" #include "refcount.h" #include "yacas/mp/zz.hpp" #include using namespace yacas; LispObject* GcdInteger(LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment); LispObject* ModFloat( LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment, int aPrecision); LispObject* PowerFloat(LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment,int aPrecision); LispObject* ShiftLeft( LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment,int aPrecision); LispObject* ShiftRight( LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment,int aPrecision); LispObject* LispFactorial(LispObject* int1, LispEnvironment& aEnvironment,int aPrecision); /** Base number class. */ /// Main class for multiple-precision arithmetic. /// All calculations are done at given precision. Integers grow as needed, floats don't grow beyond given precision. class BigNumber: public RefCount { public: //constructors BigNumber(const std::string& aString,int aPrecision,int aBase=10); explicit BigNumber(const mp::ZZ& zz); /// copy constructor explicit BigNumber(const BigNumber& aOther); BigNumber& operator = (const BigNumber&); /// ToString : return string representation of number in aResult to given precision (base digits) void ToString(std::string& aResult, int aPrecision, int aBase=10) const; /// Give approximate representation as a double number double Double() const; //basic object manipulation bool Equals(const BigNumber& aOther) const; bool IsInt() const; bool IsSmall() const; void BecomeInt(); void BecomeFloat(int aPrecision=0); bool LessThan(const BigNumber& aOther) const; //arithmetic /// Multiply two numbers at given precision and put result in *this void Multiply(const BigNumber& aX, const BigNumber& aY, int aPrecision); /// Add two numbers at given precision and return result in *this void Add(const BigNumber& aX, const BigNumber& aY, int aPrecision); /// Negate the given number, return result in *this void Negate(const BigNumber& aX); /// Divide two numbers and return result in *this. Note: if the two arguments are integer, it should return an integer result! void Divide(const BigNumber& aX, const BigNumber& aY, int aPrecision); /// For debugging purposes, dump internal state of this object into a string void DumpDebugInfo(std::ostream&) const; /// assign self to Floor(aX) if possible void Floor(const BigNumber& aX); /// set precision (in bits) void Precision(int aPrecision); /// Bitwise operations, return result in *this. void ShiftLeft( const BigNumber& aX, int aNrToShift); void ShiftRight( const BigNumber& aX, int aNrToShift); void BitAnd(const BigNumber& aX, const BigNumber& aY); void BitOr(const BigNumber& aX, const BigNumber& aY); void BitXor(const BigNumber& aX, const BigNumber& aY); void BitNot(const BigNumber& aX); /// Bit count operation: return the number of significant bits if integer, return the binary exponent if float (shortcut for binary logarithm) /// give bit count as a platform integer signed long BitCount() const; /// Give sign (-1, 0, 1) int Sign() const; inline int GetPrecision() const {return iPrecision;}; private: int iPrecision; friend LispObject* GcdInteger(LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment); friend LispObject* SqrtFloat(LispObject* int1, LispEnvironment& aEnvironment,int aPrecision); friend LispObject* PowerFloat(LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment,int aPrecision); std::unique_ptr iNumber; std::unique_ptr _zz; }; /// bits_to_digits and digits_to_bits, utility functions /// to convert the number of digits in some base (usually 10) to bits and back // lookup table for Ln(n)/Ln(2) // table range is from 2 to this value: unsigned log2_table_range(); // convert the number of digits in given base to the number of bits, and back. // need to round the number of digits. // These functions only work for aBase inside the allowed table range. unsigned long digits_to_bits(unsigned long aDigits, unsigned aBase); unsigned long bits_to_digits(unsigned long abits, unsigned aBase); #endif ================================================ FILE: cyacas/libyacas/include/yacas/patcher.h ================================================ #ifndef YACAS_PATCHER_H #define YACAS_PATCHER_H #include #include #include "lispenvironment.h" void PatchLoad(const std::string&, std::ostream&, LispEnvironment&); #endif ================================================ FILE: cyacas/libyacas/include/yacas/patternclass.h ================================================ #ifndef YACAS_PATTERNCLASS_H #define YACAS_PATTERNCLASS_H #include "lispobject.h" #include "genericobject.h" #include "patterns.h" #include "noncopyable.h" /// Wrapper for YacasPatternPredicateBase. /// This class allows a YacasPatternPredicateBase to be put in a /// LispGenericObject. class PatternClass final: public GenericClass, NonCopyable { public: PatternClass(YacasPatternPredicateBase* aPatternMatcher); ~PatternClass(); bool Matches(LispEnvironment& aEnvironment, LispPtr& aArguments); bool Matches(LispEnvironment& aEnvironment, LispPtr* aArguments); const char* TypeName() const override; protected: YacasPatternPredicateBase* iPatternMatcher; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/patterns.h ================================================ #ifndef YACAS_PATTERNS_H #define YACAS_PATTERNS_H /// \file /// Pattern matching code. /// /// General idea: have a class that can match function parameters /// to a pattern, check for predicates on the arguments, and return /// whether there was a match. /// /// First the pattern is mapped onto the arguments. Then local variables /// are set. Then the predicates are called. If they all return true, /// Then the pattern matches, and the locals can stay (the body is expected /// to use these variables). #include "lispenvironment.h" #include "noncopyable.h" #include "numbers.h" #include /// Abstract class for matching one argument to a pattern. class YacasParamMatcherBase { public: /// Destructor. virtual ~YacasParamMatcherBase() = default; /// Check whether some expression matches to the pattern. /// \param aEnvironment the underlying Lisp environment. /// \param aExpression the expression to test. /// \param arguments (input/output) actual values of the pattern /// variables for \a aExpression. virtual bool ArgumentMatches(LispEnvironment& aEnvironment, LispPtr& aExpression, LispPtr* arguments) const = 0; }; /// Class for matching an expression to a given atom. class MatchAtom : public YacasParamMatcherBase { public: explicit MatchAtom(const LispString* aString); bool ArgumentMatches(LispEnvironment& aEnvironment, LispPtr& aExpression, LispPtr* arguments) const override; protected: const LispString* iString; }; inline MatchAtom::MatchAtom(const LispString* aString): iString(aString) { } /// Class for matching an expression to a given number. class MatchNumber : public YacasParamMatcherBase { public: explicit MatchNumber(BigNumber* aNumber); bool ArgumentMatches(LispEnvironment& aEnvironment, LispPtr& aExpression, LispPtr* arguments) const override; protected: RefPtr iNumber; }; inline MatchNumber::MatchNumber(BigNumber* aNumber): iNumber(aNumber) { } /// Class for matching against a list of YacasParamMatcherBase objects. class MatchSubList final: public YacasParamMatcherBase, NonCopyable { public: explicit MatchSubList(const std::vector&& aMatchers); ~MatchSubList() override; bool ArgumentMatches( LispEnvironment& aEnvironment, LispPtr& aExpression, LispPtr* arguments) const override; protected: std::vector iMatchers; }; inline MatchSubList::MatchSubList(const std::vector&& aMatchers): iMatchers(aMatchers) { } inline MatchSubList::~MatchSubList() { for (const YacasParamMatcherBase* m: iMatchers) delete m; } /// Class for matching against a pattern variable. class MatchVariable final: public YacasParamMatcherBase { public: explicit MatchVariable(int aVarIndex); /// Matches an expression against the pattern variable. /// \param aEnvironment the underlying Lisp environment. /// \param aExpression the expression to test. /// \param arguments (input/output) actual values of the pattern /// variables for \a aExpression. /// /// If entry #iVarIndex in \a arguments is still empty, the /// pattern matches and \a aExpression is stored in this /// entry. Otherwise, the pattern only matches if the entry equals /// \a aExpression. bool ArgumentMatches(LispEnvironment& aEnvironment, LispPtr& aExpression, LispPtr* arguments) const override; protected: /// Index of variable in YacasPatternPredicateBase::iVariables. int iVarIndex; }; inline MatchVariable::MatchVariable(int aVarIndex): iVarIndex(aVarIndex) { } /// Class that matches function arguments to a pattern. /// This class (specifically, the Matches() member function) can match /// function parameters to a pattern, check for predicates on the /// arguments, and return whether there was a match. class YacasPatternPredicateBase: NonCopyable { public: /// Constructor. /// \param aEnvironment the underlying Lisp environment /// \param aPattern Lisp expression containing the pattern /// \param aPostPredicate Lisp expression containing the /// postpredicate /// /// The function MakePatternMatcher() is called for every argument /// in \a aPattern, and the resulting pattern matchers are /// collected in #iParamMatchers. Additionally, \a aPostPredicate /// is copied, and the copy is added to #iPredicates. YacasPatternPredicateBase(LispEnvironment& aEnvironment, LispPtr& aPattern, LispPtr& aPostPredicate); /// Destructor. virtual ~YacasPatternPredicateBase(); /// Try to match the pattern against \a aArguments. /// First, every argument in \a aArguments is matched against the /// corresponding YacasParamMatcherBase in #iParamMatches. If any /// match fails, Matches() returns false. Otherwise, a temporary /// LispLocalFrame is constructed, then SetPatternVariables() and /// CheckPredicates() are called, and then the LispLocalFrame is /// immediately deleted. If CheckPredicates() returns false, this /// function also returns false. Otherwise, SetPatternVariables() /// is called again, but now in the current LispLocalFrame, and /// this function returns true. bool Matches(LispEnvironment& aEnvironment, LispPtr& aArguments); /// Try to match the pattern against \a aArguments. /// This function does the same as Matches(LispEnvironment&,LispPtr&), /// but differs in the type of the arguments. bool Matches(LispEnvironment& aEnvironment, LispPtr* aArguments); protected: /// Construct a pattern matcher out of a Lisp expression. /// The result of this function depends on the value of \a aPattern: /// - If \a aPattern is a number, the corresponding MatchNumber is /// constructed and returned. /// - If \a aPattern is an atom, the corresponding MatchAtom is /// constructed and returned. /// - If \a aPattern is a list of the form ( _ var ), /// where \c var is an atom, LookUp() is called on \c var. Then /// the corresponding MatchVariable is constructed and returned. /// - If \a aPattern is a list of the form ( _ var expr ), /// where \c var is an atom, LookUp() is called on \c var. Then, /// \a expr is appended to #iPredicates. Finally, the /// correspoding MatchVariable is constructed and returned. /// - If \a aPattern is a list of another form, this function /// calls itself on any of the entries in this list. The /// resulting YacasParamMatcherBase objects are collected in a /// MatchSubList, which is returned. /// - Otherwise, this function returns #nullptr. const YacasParamMatcherBase* MakeParamMatcher(LispEnvironment& aEnvironment, LispObject* aPattern); /// Look up a variable name in #iVariables /// \returns index in #iVariables array where \a aVariable /// appears. /// /// If \a aVariable is not in #iVariables, it is added. int LookUp(const LispString* aVariable); protected: /// Set local variables corresponding to the pattern variables. /// This function goes through the #iVariables array. A local /// variable is made for every entry in the array, and the /// corresponding argument is assigned to it. void SetPatternVariables(LispEnvironment& aEnvironment, LispPtr* arguments); /// Check whether all predicates are true. /// This function goes through all predicates in #iPredicates, and /// evaluates them. It returns #false if at least one /// of these results IsFalse(). An error is raised if any result /// neither IsTrue() nor IsFalse(). bool CheckPredicates(LispEnvironment& aEnvironment); protected: /// List of parameter matches, one for every parameter. std::vector iParamMatchers; /// List of variables appearing in the pattern. std::vector iVariables; /// List of predicates which need to be true for a match. std::vector iPredicates; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/platfileio.h ================================================ #ifndef YACAS_PLATFILEIO_H #define YACAS_PLATFILEIO_H #include "lispenvironment.h" #include "noncopyable.h" #include #include class LispLocalFile: NonCopyable { public: LispLocalFile( LispEnvironment& environment, const std::string& fname, bool read, const std::vector& dirs); virtual ~LispLocalFile(); public: std::fstream stream; LispEnvironment& environment; }; class StdFileInput: public LispInput { public: StdFileInput(std::istream&, InputStatus& aStatus); StdFileInput(LispLocalFile& aFile,InputStatus& aStatus); char32_t Next() override; char32_t Peek() override; bool EndOfStream() const override; virtual void Rewind(); std::size_t Position() const override; void SetPosition(std::size_t) override; private: void _get() const; std::istream& _stream; std::size_t _position; mutable bool _cp_ready; mutable char32_t _cp; }; class StdUserInput final: public StdFileInput { public: StdUserInput(InputStatus& aStatus): StdFileInput(std::cin, aStatus) { } }; std::string InternalFindFile(const std::string& fname, const std::vector& dirs); #endif ================================================ FILE: cyacas/libyacas/include/yacas/platmath.h ================================================ #ifndef YACAS_PLATMATH_H #define YACAS_PLATMATH_H #include "lispenvironment.h" // // Beware the use of these functions! They cannot be guaranteed to be // // supported on any platform. // double GetDouble(LispObject* aInteger); // LispObject* Double(LispEnvironment& aEnvironment,double aValue); // LispObject* PlatArcSin(LispEnvironment& aEnvironment,LispObject* int1, int aPrecision); // LispObject* PlatLn(LispEnvironment& aEnvironment,LispObject* int1, int aPrecision); // LispObject* PlatPower(LispEnvironment& aEnvironment,LispObject* int1, LispObject* int2, // int aPrecision); // LispObject* PlatDiv(LispEnvironment& aEnvironment,LispObject* int1, LispObject* int2,int aPrecision); // LispObject* PlatIsPrime(LispEnvironment& aEnvironment,LispObject* int1, int aPrecision); // table lookup for small prime numbers unsigned primes_table_check(unsigned long p); unsigned primes_table_range(); #endif ================================================ FILE: cyacas/libyacas/include/yacas/refcount.h ================================================ #ifndef YACAS_REFCOUNT_H #define YACAS_REFCOUNT_H #include //------------------------------------------------------------------------------ // RefPtr - Smart pointer for (intrusive) reference counting. // Simply, an object's reference count is the number of RefPtrs referring to it. // The RefPtr will delete the referenced object when the count reaches zero. /*TODO: this might be improved a little by having RefPtr wrap the object being pointed to so the user of RefPtr does not need to add ReferenceCount explicitly. One can use RefPtr on any arbitrary object from that moment on. */ template class RefPtr { public: // Default constructor (not explicit, so it auto-initializes) inline RefPtr() : iPtr(nullptr) {} // Construct from pointer to T /*explicit*/ RefPtr(T* ptr) : iPtr(ptr) { if (ptr) { ptr->_use_count++; } } // Copy constructor RefPtr(const RefPtr &refPtr) : iPtr(refPtr.ptr()) { if (iPtr) { iPtr->_use_count++; } } // Destructor ~RefPtr() { if (iPtr && !--iPtr->_use_count) delete iPtr; } // Assignment from pointer RefPtr &operator=(T *ptr) { if (ptr) ptr->_use_count++; if (iPtr && !--iPtr->_use_count) delete iPtr; iPtr = ptr; return *this; } // Assignment from another RefPtr &operator=(const RefPtr &refPtr) { return this->operator=(refPtr.ptr()); } operator T*() const { return iPtr; } // implicit conversion to pointer to T T &operator*() const { return *iPtr; } // so (*refPtr) is a reference to T T *operator->() const { return iPtr; } // so (refPtr->member) accesses T's member T *ptr() const { return iPtr; } // so (refPtr.ptr()) returns the pointer to T (boost calls this method 'get') bool operator!() const { return !iPtr; } // is null pointer private: T *iPtr; }; class RefCount { public: RefCount(): _use_count(0) {} RefCount(const RefCount&): _use_count(0) {} virtual ~RefCount() = default; RefCount& operator = (const RefCount&) { return *this; } unsigned use_count() const { return _use_count; } private: template friend class RefPtr; mutable unsigned _use_count; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/standard.h ================================================ #ifndef YACAS_STANDARD_H #define YACAS_STANDARD_H #include "lispobject.h" #include "lispenvironment.h" #include "lisphash.h" #include "lispatom.h" #include "numbers.h" // Prototypes class LispHashTable; bool InternalIsList(const LispEnvironment& env, const LispPtr& aPtr); bool InternalIsString(const LispString* aOriginal); std::string InternalUnstringify(const std::string& s); int InternalAsciiToInt(const LispString& aString); bool IsNumber(const std::string& s, bool aAllowFloat); void InternalNth(LispPtr& aResult, const LispPtr& aArg, int n); void InternalTail(LispPtr& aResult, const LispPtr& aArg); void InternalAssociate(LispPtr& aResult, const LispPtr& aKey, const LispPtr& aAssociationList); void InternalReverseList(LispPtr& aResult, const LispPtr& aOriginal); void InternalFlatCopy(LispPtr& aResult, const LispPtr& aOriginal); std::size_t InternalListLength(const LispPtr& aOriginal); bool InternalStrictTotalOrder(const LispEnvironment& env, const LispPtr& e1, const LispPtr& e2); bool InternalEquals(const LispEnvironment& aEnvironment, const LispPtr& aExpression1, const LispPtr& aExpression2); inline LispPtr& Argument(LispPtr& cur, int n); inline void InternalTrue(const LispEnvironment& aEnvironment, LispPtr& aResult); inline void InternalFalse(const LispEnvironment& aEnvironment, LispPtr& aResult); inline void InternalBoolean(LispEnvironment& aEnvironment, LispPtr& aResult, bool aValue); inline bool IsTrue(LispEnvironment& aEnvironment, const LispPtr& aExpression); inline bool IsFalse(LispEnvironment& aEnvironment, const LispPtr& aExpression); inline void InternalNot(LispPtr& aResult, LispEnvironment& aEnvironment, LispPtr& aExpression); void DoInternalLoad(LispEnvironment& aEnvironment,LispInput* aInput); void InternalLoad(LispEnvironment& aEnvironment, const std::string& aFileName); void InternalUse(LispEnvironment& aEnvironment, const std::string& aFileName); void InternalApplyString(LispEnvironment& aEnvironment, LispPtr& aResult, const LispString* aOperator,LispPtr& aArgs); void InternalApplyPure(LispPtr& oper,LispPtr& args2,LispPtr& aResult,LispEnvironment& aEnvironment); void InternalEvalString(LispEnvironment& aEnvironment, LispPtr& aResult, const char* aString); class LispObjectAdder { public: LispObjectAdder(LispObject* aPtr) : iPtr(aPtr) {}; LispObject* iPtr; }; LispObject* operator+(const LispObjectAdder& left, const LispObjectAdder& right); void ParseExpression(LispPtr& aResult, const char* aString, LispEnvironment& aEnvironment); void ReturnUnEvaluated(LispPtr& aResult,LispPtr& aArguments, LispEnvironment& aEnvironment); /** PrintExpression : print an expression into a string, limiting it to a maximum number of characters. If aMaxChars is less than zero, the result is not truncated. */ void PrintExpression(LispString& aResult, LispPtr& aExpression, LispEnvironment& aEnvironment, std::size_t aMaxChars); const LispString* SymbolName(LispEnvironment& aEnvironment, const std::string& aSymbol); #include "standard.inl" #endif ================================================ FILE: cyacas/libyacas/include/yacas/standard.inl ================================================ inline LispPtr& Argument(LispPtr& cur, int n) { assert(n>=0); LispPtr* loop = &cur; while(n--) loop = &(*loop)->Nixed(); return *loop; } // Boolean operations inline void InternalTrue(const LispEnvironment& aEnvironment, LispPtr& aResult) { aResult = (aEnvironment.iTrue->Copy()); } inline void InternalFalse(const LispEnvironment& aEnvironment, LispPtr& aResult) { aResult = (aEnvironment.iFalse->Copy()); } inline void InternalBoolean(LispEnvironment& aEnvironment, LispPtr& aResult, bool aValue) { if (aValue) { InternalTrue(aEnvironment, aResult); } else { InternalFalse(aEnvironment, aResult); } } inline bool IsTrue(LispEnvironment& aEnvironment, const LispPtr& aExpression) { assert(aExpression); return aExpression->String() == aEnvironment.iTrue->String(); } inline bool IsFalse(LispEnvironment& aEnvironment, const LispPtr& aExpression) { assert(aExpression); return aExpression->String() == aEnvironment.iFalse->String(); } inline void InternalNot(LispPtr& aResult, LispEnvironment& aEnvironment, LispPtr& aExpression) { if (IsTrue(aEnvironment, aExpression)) { InternalFalse(aEnvironment,aResult); } else { if (!IsFalse(aEnvironment, aExpression)) throw LispErrInvalidArg(); InternalTrue(aEnvironment,aResult); } } ================================================ FILE: cyacas/libyacas/include/yacas/string_utils.h ================================================ #ifndef STRING_UTILS_H #define STRING_UTILS_H #include #include #include #include #include inline std::string stringify(const std::string& s) { return "\"" + s + "\""; } inline std::string& ltrim(std::string& s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int c) { return !std::isspace(c); })); return s; } inline std::string& rtrim(std::string& s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); return s; } inline std::string& trim(std::string& s) { return ltrim(rtrim(s)); } #endif ================================================ FILE: cyacas/libyacas/include/yacas/stringio.h ================================================ /** \file stringio.h * definitions of input output classes that read and write from string. */ #ifndef YACAS_STRINGIO_H #define YACAS_STRINGIO_H #include "lispio.h" #include "utf8.h" #include class StringInput final: public LispInput { public: StringInput(const std::string&, InputStatus&); char32_t Next() override; char32_t Peek() override; bool EndOfStream() const override; std::size_t Position() const override; void SetPosition(std::size_t aPosition) override; protected: std::string _string; std::string::const_iterator _current; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/substitute.h ================================================ #ifndef YACAS_SUBSTITUTE_H #define YACAS_SUBSTITUTE_H #include "lispobject.h" #include "lispenvironment.h" #include /** Behaviour for substituting sub-expressions. */ class SubstBehaviourBase { public: virtual ~SubstBehaviourBase() = default; virtual bool Matches(LispPtr& aResult, LispPtr& aElement) = 0; }; /** main routine that can perform substituting of expressions */ void InternalSubstitute(LispPtr& aTarget, LispPtr& aSource, SubstBehaviourBase& aBehaviour); /** Substing one expression for another. The simplest form * of substitution */ class SubstBehaviour final: public SubstBehaviourBase { public: SubstBehaviour(LispEnvironment& aEnvironment,LispPtr& aToMatch, LispPtr& aToReplaceWith); bool Matches(LispPtr& aResult, LispPtr& aElement) override; private: LispEnvironment& iEnvironment; LispPtr& iToMatch; LispPtr& iToReplaceWith; }; /** subst behaviour for changing the local variables to have unique * names. */ class LocalSymbolBehaviour final: public SubstBehaviourBase { public: LocalSymbolBehaviour( LispEnvironment& aEnvironment, const std::vector&& aOriginalNames, const std::vector&& aNewNames); bool Matches(LispPtr& aResult, LispPtr& aElement) override; private: LispEnvironment& iEnvironment; std::vector iOriginalNames; std::vector iNewNames; }; /** subst behaviour for backquote mechanism as in LISP. * When typing `(...) all occurrences of @a will be * replaced with: * 1) a evaluated if a is an atom * 2) function call with function name replaced by evaluated * head of function if a is a function. For instance, if * a is f(x) and f is g, then f(x) gets replaced by g(x) */ class BackQuoteBehaviour final: public SubstBehaviourBase { public: BackQuoteBehaviour(LispEnvironment& aEnvironment) : iEnvironment(aEnvironment) {}; bool Matches(LispPtr& aResult, LispPtr& aElement) override; private: LispEnvironment& iEnvironment; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/tokenizer.h ================================================ /** \file tokenizer.h * definitions of input output classes that read and write from string. */ #ifndef YACAS_TOKENIZER_H #define YACAS_TOKENIZER_H #include "lispio.h" #include #include #include class LispTokenizer { public: virtual ~LispTokenizer() = default; /// NextToken returns a string representing the next token, /// or an empty list. virtual std::string NextToken(LispInput& aInput); }; // utility functions #ifdef YACAS_UINT32_T_IN_GLOBAL_NAMESPACE bool IsAlpha(uint32_t c); bool IsAlNum(uint32_t c); #else bool IsAlpha(std::uint32_t c); bool IsAlNum(std::uint32_t c); #endif bool IsSymbolic(char c); #endif ================================================ FILE: cyacas/libyacas/include/yacas/utf8/checked.h ================================================ // Copyright 2006-2016 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "core.h" #include namespace utf8 { // Base for the exceptions that may be thrown from the library class exception : public ::std::exception { }; // Exceptions that may be thrown from the library functions. class invalid_code_point : public exception { utfchar32_t cp; public: invalid_code_point(utfchar32_t codepoint) : cp(codepoint) {} virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; } utfchar32_t code_point() const {return cp;} }; class invalid_utf8 : public exception { utfchar8_t u8; public: invalid_utf8 (utfchar8_t u) : u8(u) {} invalid_utf8 (char c) : u8(static_cast(c)) {} virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; } utfchar8_t utf8_octet() const {return u8;} }; class invalid_utf16 : public exception { utfchar16_t u16; public: invalid_utf16 (utfchar16_t u) : u16(u) {} virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; } utfchar16_t utf16_word() const {return u16;} }; class not_enough_room : public exception { public: virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; } }; /// The library API - functions intended to be called by the users template octet_iterator append(utfchar32_t cp, octet_iterator result) { if (!utf8::internal::is_code_point_valid(cp)) throw invalid_code_point(cp); return internal::append(cp, result); } inline void append(utfchar32_t cp, std::string& s) { append(cp, std::back_inserter(s)); } template word_iterator append16(utfchar32_t cp, word_iterator result) { if (!utf8::internal::is_code_point_valid(cp)) throw invalid_code_point(cp); return internal::append16(cp, result); } template output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, utfchar32_t replacement) { while (start != end) { octet_iterator sequence_start = start; internal::utf_error err_code = utf8::internal::validate_next(start, end); switch (err_code) { case internal::UTF8_OK : for (octet_iterator it = sequence_start; it != start; ++it) *out++ = *it; break; case internal::NOT_ENOUGH_ROOM: out = utf8::append (replacement, out); start = end; break; case internal::INVALID_LEAD: out = utf8::append (replacement, out); ++start; break; case internal::INCOMPLETE_SEQUENCE: case internal::OVERLONG_SEQUENCE: case internal::INVALID_CODE_POINT: out = utf8::append (replacement, out); ++start; // just one replacement mark for the sequence while (start != end && utf8::internal::is_trail(*start)) ++start; break; } } return out; } template inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) { static const utfchar32_t replacement_marker = static_cast(utf8::internal::mask16(0xfffd)); return utf8::replace_invalid(start, end, out, replacement_marker); } inline std::string replace_invalid(const std::string& s, utfchar32_t replacement) { std::string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); return result; } inline std::string replace_invalid(const std::string& s) { std::string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result)); return result; } template utfchar32_t next(octet_iterator& it, octet_iterator end) { utfchar32_t cp = 0; internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); switch (err_code) { case internal::UTF8_OK : break; case internal::NOT_ENOUGH_ROOM : throw not_enough_room(); case internal::INVALID_LEAD : case internal::INCOMPLETE_SEQUENCE : case internal::OVERLONG_SEQUENCE : throw invalid_utf8(static_cast(*it)); case internal::INVALID_CODE_POINT : throw invalid_code_point(cp); } return cp; } template utfchar32_t next16(word_iterator& it, word_iterator end) { utfchar32_t cp = 0; internal::utf_error err_code = utf8::internal::validate_next16(it, end, cp); if (err_code == internal::NOT_ENOUGH_ROOM) throw not_enough_room(); return cp; } template utfchar32_t peek_next(octet_iterator it, octet_iterator end) { return utf8::next(it, end); } template utfchar32_t prior(octet_iterator& it, octet_iterator start) { // can't do much if it == start if (it == start) throw not_enough_room(); octet_iterator end = it; // Go back until we hit either a lead octet or start while (utf8::internal::is_trail(*(--it))) if (it == start) throw invalid_utf8(*it); // error - no lead byte in the sequence return utf8::peek_next(it, end); } template void advance (octet_iterator& it, distance_type n, octet_iterator end) { const distance_type zero(0); if (n < zero) { // backward for (distance_type i = n; i < zero; ++i) utf8::prior(it, end); } else { // forward for (distance_type i = zero; i < n; ++i) utf8::next(it, end); } } template typename std::iterator_traits::difference_type distance (octet_iterator first, octet_iterator last) { typename std::iterator_traits::difference_type dist; for (dist = 0; first < last; ++dist) utf8::next(first, last); return dist; } template octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) { while (start != end) { utfchar32_t cp = static_cast(utf8::internal::mask16(*start++)); // Take care of surrogate pairs first if (utf8::internal::is_lead_surrogate(cp)) { if (start != end) { const utfchar32_t trail_surrogate = static_cast(utf8::internal::mask16(*start++)); if (utf8::internal::is_trail_surrogate(trail_surrogate)) cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; else throw invalid_utf16(static_cast(trail_surrogate)); } else throw invalid_utf16(static_cast(cp)); } // Lone trail surrogate else if (utf8::internal::is_trail_surrogate(cp)) throw invalid_utf16(static_cast(cp)); result = utf8::append(cp, result); } return result; } template u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) { while (start < end) { const utfchar32_t cp = utf8::next(start, end); if (cp > 0xffff) { //make a surrogate pair *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); } else *result++ = static_cast(cp); } return result; } template octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) { while (start != end) result = utf8::append(*(start++), result); return result; } template u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) { while (start < end) (*result++) = utf8::next(start, end); return result; } // The iterator class template class iterator { octet_iterator it; octet_iterator range_start; octet_iterator range_end; public: typedef utfchar32_t value_type; typedef utfchar32_t* pointer; typedef utfchar32_t& reference; typedef std::ptrdiff_t difference_type; typedef std::bidirectional_iterator_tag iterator_category; iterator () {} explicit iterator (const octet_iterator& octet_it, const octet_iterator& rangestart, const octet_iterator& rangeend) : it(octet_it), range_start(rangestart), range_end(rangeend) { if (it < range_start || it > range_end) throw std::out_of_range("Invalid utf-8 iterator position"); } // the default "big three" are OK octet_iterator base () const { return it; } utfchar32_t operator * () const { octet_iterator temp = it; return utf8::next(temp, range_end); } bool operator == (const iterator& rhs) const { if (range_start != rhs.range_start || range_end != rhs.range_end) throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); return (it == rhs.it); } bool operator != (const iterator& rhs) const { return !(operator == (rhs)); } iterator& operator ++ () { utf8::next(it, range_end); return *this; } iterator operator ++ (int) { iterator temp = *this; utf8::next(it, range_end); return temp; } iterator& operator -- () { utf8::prior(it, range_start); return *this; } iterator operator -- (int) { iterator temp = *this; utf8::prior(it, range_start); return temp; } }; // class iterator } // namespace utf8 #if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later #include "cpp20.h" #elif UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later #include "cpp17.h" #elif UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later #include "cpp11.h" #endif // C++ 11 or later #endif //header guard ================================================ FILE: cyacas/libyacas/include/yacas/utf8/core.h ================================================ // Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include #include #include // Determine the C++ standard version. // If the user defines UTF_CPP_CPLUSPLUS, use that. // Otherwise, trust the unreliable predefined macro __cplusplus #if !defined UTF_CPP_CPLUSPLUS #define UTF_CPP_CPLUSPLUS __cplusplus #endif #if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later #define UTF_CPP_OVERRIDE override #define UTF_CPP_NOEXCEPT noexcept #define UTF_CPP_STATIC_ASSERT(condition) static_assert(condition, "UTFCPP static assert"); #else // C++ 98/03 #define UTF_CPP_OVERRIDE #define UTF_CPP_NOEXCEPT throw() // Not worth simulating static_assert: #define UTF_CPP_STATIC_ASSERT(condition) (void)(condition); #endif // C++ 11 or later namespace utf8 { // The typedefs for 8-bit, 16-bit and 32-bit code units #if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later #if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later typedef char8_t utfchar8_t; #else // C++ 11/14/17 typedef unsigned char utfchar8_t; #endif typedef char16_t utfchar16_t; typedef char32_t utfchar32_t; #else // C++ 98/03 typedef unsigned char utfchar8_t; typedef unsigned short utfchar16_t; typedef unsigned int utfchar32_t; #endif // C++ 11 or later // Helper code - not intended to be directly called by the library users. May be changed at any time namespace internal { // Unicode constants // Leading (high) surrogates: 0xd800 - 0xdbff // Trailing (low) surrogates: 0xdc00 - 0xdfff const utfchar16_t LEAD_SURROGATE_MIN = 0xd800u; const utfchar16_t LEAD_SURROGATE_MAX = 0xdbffu; const utfchar16_t TRAIL_SURROGATE_MIN = 0xdc00u; const utfchar16_t TRAIL_SURROGATE_MAX = 0xdfffu; const utfchar16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10) const utfchar32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN // Maximum valid value for a Unicode code point const utfchar32_t CODE_POINT_MAX = 0x0010ffffu; template inline utfchar8_t mask8(octet_type oc) { return static_cast(0xff & oc); } template inline utfchar16_t mask16(u16_type oc) { return static_cast(0xffff & oc); } template inline bool is_trail(octet_type oc) { return ((utf8::internal::mask8(oc) >> 6) == 0x2); } inline bool is_lead_surrogate(utfchar32_t cp) { return (cp >= static_cast(LEAD_SURROGATE_MIN) && cp <= static_cast(LEAD_SURROGATE_MAX)); } inline bool is_trail_surrogate(utfchar32_t cp) { return (cp >= static_cast(TRAIL_SURROGATE_MIN) && cp <= static_cast(TRAIL_SURROGATE_MAX)); } inline bool is_surrogate(utfchar32_t cp) { return (cp >= static_cast(LEAD_SURROGATE_MIN) && cp <= static_cast(TRAIL_SURROGATE_MAX)); } inline bool is_code_point_valid(utfchar32_t cp) { return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); } inline bool is_in_bmp(utfchar32_t cp) { return cp < utfchar32_t(0x10000); } template int sequence_length(octet_iterator lead_it) { const utfchar8_t lead = utf8::internal::mask8(*lead_it); if (lead < 0x80) return 1; else if ((lead >> 5) == 0x6) return 2; else if ((lead >> 4) == 0xe) return 3; else if ((lead >> 3) == 0x1e) return 4; else return 0; } inline bool is_overlong_sequence(utfchar32_t cp, int length) { if (cp < 0x80) { if (length != 1) return true; } else if (cp < 0x800) { if (length != 2) return true; } else if (cp < 0x10000) { if (length != 3) return true; } return false; } enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; /// Helper for get_sequence_x template utf_error increase_safely(octet_iterator& it, const octet_iterator end) { if (++it == end) return NOT_ENOUGH_ROOM; if (!utf8::internal::is_trail(*it)) return INCOMPLETE_SEQUENCE; return UTF8_OK; } #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} /// get_sequence_x functions decode utf-8 sequences of the length x template utf_error get_sequence_1(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = static_cast(utf8::internal::mask8(*it)); return UTF8_OK; } template utf_error get_sequence_2(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = static_cast(utf8::internal::mask8(*it)); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); return UTF8_OK; } template utf_error get_sequence_3(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = static_cast(utf8::internal::mask8(*it)); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = static_cast(code_point + ((*it) & 0x3f)); return UTF8_OK; } template utf_error get_sequence_4(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = static_cast(utf8::internal::mask8(*it)); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = static_cast(code_point + ((utf8::internal::mask8(*it) << 6) & 0xfff)); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = static_cast(code_point + ((*it) & 0x3f)); return UTF8_OK; } #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR template utf_error validate_next(octet_iterator& it, octet_iterator end, utfchar32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; // Save the original value of it so we can go back in case of failure // Of course, it does not make much sense with i.e. stream iterators octet_iterator original_it = it; utfchar32_t cp = 0; // Determine the sequence length based on the lead octet const int length = utf8::internal::sequence_length(it); // Get trail octets and calculate the code point utf_error err = UTF8_OK; switch (length) { case 0: return INVALID_LEAD; case 1: err = utf8::internal::get_sequence_1(it, end, cp); break; case 2: err = utf8::internal::get_sequence_2(it, end, cp); break; case 3: err = utf8::internal::get_sequence_3(it, end, cp); break; case 4: err = utf8::internal::get_sequence_4(it, end, cp); break; } if (err == UTF8_OK) { // Decoding succeeded. Now, security checks... if (utf8::internal::is_code_point_valid(cp)) { if (!utf8::internal::is_overlong_sequence(cp, length)){ // Passed! Return here. code_point = cp; ++it; return UTF8_OK; } else err = OVERLONG_SEQUENCE; } else err = INVALID_CODE_POINT; } // Failure branch - restore the original value of the iterator it = original_it; return err; } template inline utf_error validate_next(octet_iterator& it, octet_iterator end) { utfchar32_t ignored; return utf8::internal::validate_next(it, end, ignored); } template utf_error validate_next16(word_iterator& it, word_iterator end, utfchar32_t& code_point) { // Make sure the iterator dereferences a large enough type typedef typename std::iterator_traits::value_type word_type; UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t)); // Check the edge case: if (it == end) return NOT_ENOUGH_ROOM; // Save the original value of it so we can go back in case of failure // Of course, it does not make much sense with i.e. stream iterators word_iterator original_it = it; utf_error err = UTF8_OK; const utfchar16_t first_word = *it++; if (!is_surrogate(first_word)) { code_point = first_word; return UTF8_OK; } else { if (it == end) err = NOT_ENOUGH_ROOM; else if (is_lead_surrogate(first_word)) { const utfchar16_t second_word = *it++; if (is_trail_surrogate(static_cast(second_word))) { code_point = static_cast(first_word << 10) + static_cast(second_word) + SURROGATE_OFFSET; return UTF8_OK; } else err = INCOMPLETE_SEQUENCE; } else { err = INVALID_LEAD; } } // error branch it = original_it; return err; } // Internal implementation of both checked and unchecked append() function // This function will be invoked by the overloads below, as they will know // the octet_type. template octet_iterator append(utfchar32_t cp, octet_iterator result) { if (cp < 0x80) // one octet *(result++) = static_cast(cp); else if (cp < 0x800) { // two octets *(result++) = static_cast((cp >> 6) | 0xc0); *(result++) = static_cast((cp & 0x3f) | 0x80); } else if (cp < 0x10000) { // three octets *(result++) = static_cast((cp >> 12) | 0xe0); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } else { // four octets *(result++) = static_cast((cp >> 18) | 0xf0); *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } return result; } // One of the following overloads will be invoked from the API calls // A simple (but dangerous) case: the caller appends byte(s) to a char array inline char* append(utfchar32_t cp, char* result) { return append(cp, result); } // Hopefully, most common case: the caller uses back_inserter // i.e. append(cp, std::back_inserter(str)); template std::back_insert_iterator append (utfchar32_t cp, std::back_insert_iterator result) { return append, typename container_type::value_type>(cp, result); } // The caller uses some other kind of output operator - not covered above // Note that in this case we are not able to determine octet_type // so we assume it's utfchar8_t; that can cause a conversion warning if we are wrong. template octet_iterator append(utfchar32_t cp, octet_iterator result) { return append(cp, result); } // Internal implementation of both checked and unchecked append16() function // This function will be invoked by the overloads below, as they will know // the word_type. template word_iterator append16(utfchar32_t cp, word_iterator result) { UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t)); if (is_in_bmp(cp)) *(result++) = static_cast(cp); else { // Code points from the supplementary planes are encoded via surrogate pairs *(result++) = static_cast(LEAD_OFFSET + (cp >> 10)); *(result++) = static_cast(TRAIL_SURROGATE_MIN + (cp & 0x3FF)); } return result; } // Hopefully, most common case: the caller uses back_inserter // i.e. append16(cp, std::back_inserter(str)); template std::back_insert_iterator append16 (utfchar32_t cp, std::back_insert_iterator result) { return append16, typename container_type::value_type>(cp, result); } // The caller uses some other kind of output operator - not covered above // Note that in this case we are not able to determine word_type // so we assume it's utfchar16_t; that can cause a conversion warning if we are wrong. template word_iterator append16(utfchar32_t cp, word_iterator result) { return append16(cp, result); } } // namespace internal /// The library API - functions intended to be called by the users // Byte order mark const utfchar8_t bom[] = {0xef, 0xbb, 0xbf}; template octet_iterator find_invalid(octet_iterator start, octet_iterator end) { octet_iterator result = start; while (result != end) { utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); if (err_code != internal::UTF8_OK) return result; } return result; } inline const char* find_invalid(const char* str) { const char* end = str + std::strlen(str); return find_invalid(str, end); } inline std::size_t find_invalid(const std::string& s) { std::string::const_iterator invalid = find_invalid(s.begin(), s.end()); return (invalid == s.end()) ? std::string::npos : static_cast(invalid - s.begin()); } template inline bool is_valid(octet_iterator start, octet_iterator end) { return (utf8::find_invalid(start, end) == end); } inline bool is_valid(const char* str) { return (*(utf8::find_invalid(str)) == '\0'); } inline bool is_valid(const std::string& s) { return is_valid(s.begin(), s.end()); } template inline bool starts_with_bom (octet_iterator it, octet_iterator end) { return ( ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) ); } inline bool starts_with_bom(const std::string& s) { return starts_with_bom(s.begin(), s.end()); } } // namespace utf8 #endif // header guard ================================================ FILE: cyacas/libyacas/include/yacas/utf8/cpp11.h ================================================ // Copyright 2018 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1 #define UTF8_FOR_CPP_a184c22c_d012_11e8_a8d5_f2801f1b9fd1 #include "checked.h" namespace utf8 { inline void append16(utfchar32_t cp, std::u16string& s) { append16(cp, std::back_inserter(s)); } inline std::string utf16to8(const std::u16string& s) { std::string result; utf16to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u16string utf8to16(const std::string& s) { std::u16string result; utf8to16(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::string utf32to8(const std::u32string& s) { std::string result; utf32to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u32string utf8to32(const std::string& s) { std::u32string result; utf8to32(s.begin(), s.end(), std::back_inserter(result)); return result; } } // namespace utf8 #endif // header guard ================================================ FILE: cyacas/libyacas/include/yacas/utf8/cpp17.h ================================================ // Copyright 2018 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9 #define UTF8_FOR_CPP_7e906c01_03a3_4daf_b420_ea7ea952b3c9 #include "cpp11.h" namespace utf8 { inline std::string utf16to8(std::u16string_view s) { std::string result; utf16to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u16string utf8to16(std::string_view s) { std::u16string result; utf8to16(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::string utf32to8(std::u32string_view s) { std::string result; utf32to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u32string utf8to32(std::string_view s) { std::u32string result; utf8to32(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::size_t find_invalid(std::string_view s) { std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end()); return (invalid == s.end()) ? std::string_view::npos : static_cast(invalid - s.begin()); } inline bool is_valid(std::string_view s) { return is_valid(s.begin(), s.end()); } inline std::string replace_invalid(std::string_view s, char32_t replacement) { std::string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); return result; } inline std::string replace_invalid(std::string_view s) { std::string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result)); return result; } inline bool starts_with_bom(std::string_view s) { return starts_with_bom(s.begin(), s.end()); } } // namespace utf8 #endif // header guard ================================================ FILE: cyacas/libyacas/include/yacas/utf8/cpp20.h ================================================ // Copyright 2022 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_207e906c01_03a3_4daf_b420_ea7ea952b3c9 #define UTF8_FOR_CPP_207e906c01_03a3_4daf_b420_ea7ea952b3c9 #include "cpp17.h" namespace utf8 { inline std::u8string utf16tou8(const std::u16string& s) { std::u8string result; utf16to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u8string utf16tou8(std::u16string_view s) { std::u8string result; utf16to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u16string utf8to16(const std::u8string& s) { std::u16string result; utf8to16(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u16string utf8to16(const std::u8string_view& s) { std::u16string result; utf8to16(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u8string utf32tou8(const std::u32string& s) { std::u8string result; utf32to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u8string utf32tou8(const std::u32string_view& s) { std::u8string result; utf32to8(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u32string utf8to32(const std::u8string& s) { std::u32string result; utf8to32(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::u32string utf8to32(const std::u8string_view& s) { std::u32string result; utf8to32(s.begin(), s.end(), std::back_inserter(result)); return result; } inline std::size_t find_invalid(const std::u8string& s) { std::u8string::const_iterator invalid = find_invalid(s.begin(), s.end()); return (invalid == s.end()) ? std::string_view::npos : static_cast(invalid - s.begin()); } inline bool is_valid(const std::u8string& s) { return is_valid(s.begin(), s.end()); } inline std::u8string replace_invalid(const std::u8string& s, char32_t replacement) { std::u8string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); return result; } inline std::u8string replace_invalid(const std::u8string& s) { std::u8string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result)); return result; } inline bool starts_with_bom(const std::u8string& s) { return starts_with_bom(s.begin(), s.end()); } } // namespace utf8 #endif // header guard ================================================ FILE: cyacas/libyacas/include/yacas/utf8/unchecked.h ================================================ // Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "core.h" namespace utf8 { namespace unchecked { template octet_iterator append(utfchar32_t cp, octet_iterator result) { return internal::append(cp, result); } template word_iterator append16(utfchar32_t cp, word_iterator result) { return internal::append16(cp, result); } template output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, utfchar32_t replacement) { while (start != end) { octet_iterator sequence_start = start; internal::utf_error err_code = utf8::internal::validate_next(start, end); switch (err_code) { case internal::UTF8_OK : for (octet_iterator it = sequence_start; it != start; ++it) *out++ = *it; break; case internal::NOT_ENOUGH_ROOM: out = utf8::unchecked::append(replacement, out); start = end; break; case internal::INVALID_LEAD: out = utf8::unchecked::append(replacement, out); ++start; break; case internal::INCOMPLETE_SEQUENCE: case internal::OVERLONG_SEQUENCE: case internal::INVALID_CODE_POINT: out = utf8::unchecked::append(replacement, out); ++start; // just one replacement mark for the sequence while (start != end && utf8::internal::is_trail(*start)) ++start; break; } } return out; } template inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) { static const utfchar32_t replacement_marker = static_cast(utf8::internal::mask16(0xfffd)); return utf8::unchecked::replace_invalid(start, end, out, replacement_marker); } inline std::string replace_invalid(const std::string& s, utfchar32_t replacement) { std::string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement); return result; } inline std::string replace_invalid(const std::string& s) { std::string result; replace_invalid(s.begin(), s.end(), std::back_inserter(result)); return result; } template utfchar32_t next(octet_iterator& it) { utfchar32_t cp = utf8::internal::mask8(*it); switch (utf8::internal::sequence_length(it)) { case 1: break; case 2: ++it; cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); break; case 3: ++it; cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); ++it; cp = static_cast(cp + ((*it) & 0x3f)); break; case 4: ++it; cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); ++it; cp = static_cast(cp + ((utf8::internal::mask8(*it) << 6) & 0xfff)); ++it; cp = static_cast(cp + ((*it) & 0x3f)); break; } ++it; return cp; } template utfchar32_t peek_next(octet_iterator it) { return utf8::unchecked::next(it); } template utfchar32_t next16(word_iterator& it) { utfchar32_t cp = utf8::internal::mask16(*it++); if (utf8::internal::is_lead_surrogate(cp)) return (cp << 10) + *it++ + utf8::internal::SURROGATE_OFFSET; return cp; } template utfchar32_t prior(octet_iterator& it) { while (utf8::internal::is_trail(*(--it))) ; octet_iterator temp = it; return utf8::unchecked::next(temp); } template void advance(octet_iterator& it, distance_type n) { const distance_type zero(0); if (n < zero) { // backward for (distance_type i = n; i < zero; ++i) utf8::unchecked::prior(it); } else { // forward for (distance_type i = zero; i < n; ++i) utf8::unchecked::next(it); } } template typename std::iterator_traits::difference_type distance(octet_iterator first, octet_iterator last) { typename std::iterator_traits::difference_type dist; for (dist = 0; first < last; ++dist) utf8::unchecked::next(first); return dist; } template octet_iterator utf16to8(u16bit_iterator start, u16bit_iterator end, octet_iterator result) { while (start != end) { utfchar32_t cp = utf8::internal::mask16(*start++); // Take care of surrogate pairs first if (utf8::internal::is_lead_surrogate(cp)) { if (start == end) return result; utfchar32_t trail_surrogate = utf8::internal::mask16(*start++); cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; } result = utf8::unchecked::append(cp, result); } return result; } template u16bit_iterator utf8to16(octet_iterator start, octet_iterator end, u16bit_iterator result) { while (start < end) { utfchar32_t cp = utf8::unchecked::next(start); if (cp > 0xffff) { //make a surrogate pair *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); } else *result++ = static_cast(cp); } return result; } template octet_iterator utf32to8(u32bit_iterator start, u32bit_iterator end, octet_iterator result) { while (start != end) result = utf8::unchecked::append(*(start++), result); return result; } template u32bit_iterator utf8to32(octet_iterator start, octet_iterator end, u32bit_iterator result) { while (start < end) (*result++) = utf8::unchecked::next(start); return result; } // The iterator class template class iterator { octet_iterator it; public: typedef utfchar32_t value_type; typedef utfchar32_t* pointer; typedef utfchar32_t& reference; typedef std::ptrdiff_t difference_type; typedef std::bidirectional_iterator_tag iterator_category; iterator () {} explicit iterator (const octet_iterator& octet_it): it(octet_it) {} // the default "big three" are OK octet_iterator base () const { return it; } utfchar32_t operator * () const { octet_iterator temp = it; return utf8::unchecked::next(temp); } bool operator == (const iterator& rhs) const { return (it == rhs.it); } bool operator != (const iterator& rhs) const { return !(operator == (rhs)); } iterator& operator ++ () { ::std::advance(it, utf8::internal::sequence_length(it)); return *this; } iterator operator ++ (int) { iterator temp = *this; ::std::advance(it, utf8::internal::sequence_length(it)); return temp; } iterator& operator -- () { utf8::unchecked::prior(it); return *this; } iterator operator -- (int) { iterator temp = *this; utf8::unchecked::prior(it); return temp; } }; // class iterator } // namespace utf8::unchecked } // namespace utf8 #endif // header guard ================================================ FILE: cyacas/libyacas/include/yacas/utf8.h ================================================ // Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 /* To control the C++ language version used by the library, you can define UTF_CPP_CPLUSPLUS macro and set it to one of the values used by the __cplusplus predefined macro. For instance, #define UTF_CPP_CPLUSPLUS 199711L will cause the UTF-8 CPP library to use only types and language features available in the C++ 98 standard. Some library features will be disabled. If you leave UTF_CPP_CPLUSPLUS undefined, it will be internally assigned to __cplusplus. */ #include "utf8/checked.h" #include "utf8/unchecked.h" #endif // header guard ================================================ FILE: cyacas/libyacas/include/yacas/xmltokenizer.h ================================================ #ifndef _xmltokenizer_h_ #define _xmltokenizer_h_ #include "tokenizer.h" class XmlTokenizer final: public LispTokenizer { public: XmlTokenizer() {} /// NextToken returns a string representing the next token, /// or an empty list. std::string NextToken(LispInput& aInput) override; }; #endif ================================================ FILE: cyacas/libyacas/include/yacas/yacas.h ================================================ /// \file /// Definitions of DefaultYacasEnvironment and CYacas. #ifndef YACAS_YACAS_H #define YACAS_YACAS_H #include "lispstring.h" #include "stringio.h" #include "tokenizer.h" #include "lisphash.h" #include "lispevalhash.h" #include "infixparser.h" #include "platfileio.h" #include "lispatom.h" #include "lispeval.h" #include "lispglobals.h" #include "lisperror.h" #include "lispuserfunc.h" #include "noncopyable.h" #include /// The default environment for a Yacas session. /// This class constructs a LispEnvironment (to be found in /// #iEnvironment), and defines the Yacas core functions. The core /// functions are listed in corefunctions.h . Examples of core /// functions are \c Head, \c Set and \c Eval. class DefaultYacasEnvironment: NonCopyable { public: explicit DefaultYacasEnvironment(std::ostream&); LispEnvironment& getEnv() {return iEnvironment;} private: std::ostream& output; LispHashTable hash; LispPrinter printer; YacasCoreCommands coreCommands; LispGlobal globals; //Define the default operators. LispOperators prefixoperators; LispOperators infixoperators; LispOperators postfixoperators; LispOperators bodiedoperators; InfixPrinter infixprinter; LispUserFunctions userFunctions; LispIdentifiers protected_symbols; LispEnvironment iEnvironment; public: StdUserInput input; }; /// The Yacas engine. /// This is the only class that applications need to use. It can /// evaluate Yacas expressions. Every instance has its own Yacas /// environment, in which the expressions are evaluated. class CYacas { public: /// Constructor explicit CYacas(std::ostream&); /// Return the underlying Yacas environment. DefaultYacasEnvironment& getDefEnv() {return environment;} /// Evaluate a Yacas expression. /// First, \p aExpression is parsed by an InfixParser. Then it is /// evaluated in the underlying Lisp environment. Finally, the /// result is printed to #iResultOutput via the pretty printer or, /// if this is not defined, via an InfixPrinter. void Evaluate(const std::string& aExpression); /// Return the result of the expression. /// This is stored in #iResult. const std::string& Result() const; /// Return the error message produced by the last evaluation. /// The error is retrieved from #environment. const std::string& Error() const; /// Whether an error occured during the last evaluation. bool IsError() const; private: /// The underlying Yacas environment DefaultYacasEnvironment environment; std::string _result; std::string _error; }; inline const std::string& CYacas::Result() const { return _result; } inline const std::string& CYacas::Error() const { return _error; } inline bool CYacas::IsError() const { return !Error().empty(); } #endif ================================================ FILE: cyacas/libyacas/src/anumber.cpp ================================================ /* Arbitrary precision arithmetic classes. These are NOT designed * to be bleeding fast, just reaonably fast, but very clean code. * */ #include "yacas/anumber.h" #include "yacas/lispstring.h" #include #include #include /* The Base... functions perform actions on the mantissa part of the * number, that is, it treats them as unsigned integers. */ void BaseAddFull(ANumber& aResult, ANumber& a1, ANumber& a2); void BaseSubtract(ANumber& aResult, ANumber& a1, ANumber& a2); void BaseMultiplyFull(ANumber& aResult, ANumber& a1, ANumber& a2); void ANumber::Print(std::ostream& os, const std::string& prefix) const { os << prefix << "\n"; os << size() << " words, " << iExp << " after point (x10^" << iTensExp << "), 10-prec " << iPrecision << "\n"; for (int i = size() - 1; i >= 0; --i) { if (iExp == i + 1) os << ".\n"; PlatWord w = at(i); PlatWord bit = (WordBase) >> 1; int k = 0; while (bit) { if ((k & 3) == 0) os << " "; k++; if (w & bit) os << "1"; else os << "0"; bit >>= 1; } os << "\n"; } } static int DigitIndex(int c) { if (std::isdigit(c)) return c - '0'; if (std::islower(c)) return c - 'a' + 10; if (std::isupper(c)) return c - 'A' + 10; // TODO error!!! return 0; } static int Digit(int c) { if (c == '.') return '.'; if (c == '-') return '-'; if (c <= 9) return '0' + c; return 'a' + c - 10; } ANumber::ANumber(int aPrecision) : iExp(0), iNegative(false), iPrecision(aPrecision), iTensExp(0) { assert(sizeof(PlatDoubleWord) >= 2 * sizeof(PlatWord)); reserve(16); push_back(0); } /* ANumber: Constructor for an arbitrary precision number. */ ANumber::ANumber(const std::string& aString, int aPrecision, int aBase) : iExp(0), iNegative(false), iPrecision(aPrecision), iTensExp(0) { reserve(16); SetTo(aString, aBase); } ANumber::ANumber(const yacas::mp::ZZ& zz, int aPrecision): std::vector(zz.to_NN().limbs().cbegin(), zz.to_NN().limbs().cend()), iExp(0), iNegative(zz.is_negative()), iPrecision(aPrecision), iTensExp(0) { reserve(16); if (zz.is_zero()) push_back(0); } std::string IntToBaseString(PlatDoubleWord aInt, int aBase) { std::string s; while (aInt != 0) { s.push_back(aInt % aBase); aInt /= aBase; } return s; } int WordDigits(int aPrecision, int aBase) { if (aPrecision == 0) return 0; int bitsPerBase = 0; while (aBase != 0) { aBase >>= 1; bitsPerBase++; } // I changed this to add two extra words at the end in stead of one, when // we moved over to scientific notation. An example of what went wrong was // typing -6.23, which for sufficiently low precision got read as 6.229999 // The original thought was that one word should be enough. This will have // to be examined more closely. return (aPrecision * bitsPerBase + 2 * WordBits) / WordBits; // return (aPrecision*bitsPerBase+WordBits)/WordBits; } void ANumber::SetTo(const std::string& str, int aBase) { clear(); reserve(16); assert(sizeof(PlatDoubleWord) >= 2 * sizeof(PlatWord)); assert(aBase <= 36); iNegative = false; iExp = 0; iTensExp = 0; const char* aString = str.c_str(); const char* endptr = aString; // Parse minus sign if (*endptr == '-') { iNegative = true; endptr++; } int endIntIndex = -1; int endFloatIndex = 0; int endNumberIndex = 0; while (aString[endNumberIndex] != '\0') { if (aString[endNumberIndex] == '.') endIntIndex = endNumberIndex; if ((aBase < 14 && aString[endNumberIndex] == 'e') || aString[endNumberIndex] == 'E') endFloatIndex = endNumberIndex; endNumberIndex++; } if (endFloatIndex == 0) endFloatIndex = endNumberIndex; if (endIntIndex == -1) endIntIndex = endFloatIndex; if (endFloatIndex == endIntIndex + 1) endFloatIndex = endIntIndex; if (endFloatIndex - endIntIndex - 1 > iPrecision) iPrecision = endFloatIndex - endIntIndex - 1; // Go to least significant digit first const char* ptr = aString + endIntIndex - 1; // Now parse the integer part of the number. ANumber factor2(iPrecision); factor2[0] = 1; while (ptr >= endptr) { ANumber term(iPrecision); term.CopyFrom(factor2); WordBaseTimesInt(term, DigitIndex(*ptr)); WordBaseAdd(*this, term); WordBaseTimesInt(factor2, aBase); ptr--; } // Parse the fraction if (endFloatIndex > endIntIndex) { std::string fraction(aString + endIntIndex + 1); // Map to a char base number const int nr = endFloatIndex - endIntIndex - 1; LispString::value_type* fractionPtr = &fraction[0]; std::reverse(fractionPtr, fractionPtr + nr); std::transform(fractionPtr, fractionPtr + nr, fractionPtr, &DigitIndex); const std::string base = IntToBaseString(WordBase, aBase); const int nrDigits = WordDigits(iPrecision, aBase); for (int i = 0; i < nrDigits; ++i) { PlatWord word = 0; std::string copied = fraction; BaseMultiply(fraction, copied, base, aBase); const int nrc = fraction.size(); PlatDoubleWord factor = 1; for (int j = nr; j < nrc; ++j) { word += fraction[j] * factor; factor = factor * aBase; } fraction.resize(nr); insert(begin(), word); iExp++; } } // Parse the E part at the end if (endNumberIndex > endFloatIndex + 1) { if (aString[endFloatIndex] == '.') endFloatIndex++; if (aString[endFloatIndex + 1] == '+') endFloatIndex++; iTensExp = std::atoi(aString + endFloatIndex + 1); } DropTrailZeroes(); } void ANumber::CopyFrom(const ANumber& aOther) { iExp = aOther.iExp; iTensExp = aOther.iTensExp; iNegative = aOther.iNegative; iPrecision = aOther.iPrecision; resize(aOther.size()); const int nr = aOther.size(); if (nr) { std::memcpy( &((*this)[0]), &(aOther[0]), nr * sizeof(ANumber::value_type)); } else { resize(1); (*this)[0] = 0; } } bool ANumber::ExactlyEqual(const ANumber& aOther) { if (iExp != aOther.iExp) return false; if (iTensExp != aOther.iTensExp) return false; if (iNegative != aOther.iNegative) return false; // if (iPrecision != aOther.iPrecision) return false; if (size() != aOther.size()) return false; // TODO there HAS to be a faster way to copy... int nr = size(); if (nr) { const ANumber::value_type* sptr = &(aOther[0]); ANumber::value_type* tptr = &((*this)[0]); while (nr--) { if (*tptr++ != *sptr++) return false; } } return true; } void Multiply(ANumber& aResult, ANumber& a1, ANumber& a2) { // Truncate zeroes (the multiplication is heavy enough as it is...) a1.DropTrailZeroes(); a2.DropTrailZeroes(); if (a1.iExp || a1.iTensExp) NormalizeFloat(a1, WordDigits(a1.iPrecision, 10)); if (a2.iExp || a2.iTensExp) NormalizeFloat(a2, WordDigits(a2.iPrecision, 10)); // this does some additional removing, as for the multiplication we don't // need any trailing zeroes at all, regardless of the value of iExp std::size_t end; end = a1.size(); while (end > 1 && a1[end - 1] == 0) end--; a1.resize(end); end = a2.size(); while (end > 1 && a2[end - 1] == 0) end--; a2.resize(end); // Multiply BaseMultiplyFull(aResult, a1, a2); // PrintNumber("Mult",aResult); // Adjust the sign aResult.iNegative = a1.IsNegative() != a2.IsNegative(); // Adjust the exponent. aResult.iExp = a1.iExp + a2.iExp; aResult.iTensExp = a1.iTensExp + a2.iTensExp; a1.Expand(); a2.Expand(); aResult.DropTrailZeroes(); if (aResult.iExp || aResult.iTensExp) NormalizeFloat(aResult, WordDigits(aResult.iPrecision, 10)); } static void BalanceFractions(ANumber& a1, ANumber& a2) { PlatWord word = 0; // ANumber a3("10e2"); // PrintNumber("a3 enter ",a3); // a3.iTensExp = 0; // PrintNumber("a3 enter ",a3); int nr; nr = a2.iExp - a1.iExp; // a2 has more decimal digits... if (nr > 0) { a1.insert(a1.begin(), nr, word); a1.iExp += nr; } nr = a1.iExp - a2.iExp; // a1 has more decimal digits... if (nr > 0) { a2.insert(a2.begin(), nr, word); a2.iExp += nr; } // TODO this is not the fastest way to multiply by 10^exp if (a1.iTensExp < a2.iTensExp) { int diff = a2.iTensExp - a1.iTensExp; a2.iTensExp = a1.iTensExp; while (diff > 0) { WordBaseTimesInt(a2, 10); diff--; } } else if (a2.iTensExp < a1.iTensExp) { int diff = a1.iTensExp - a2.iTensExp; a1.iTensExp = a2.iTensExp; while (diff > 0) { WordBaseTimesInt(a1, 10); diff--; } } } void Add(ANumber& aResult, ANumber& a1, ANumber& a2) { // if the numbers are float, make sure they are normalized if (a1.iExp || a1.iTensExp) NormalizeFloat(a1, WordDigits(a1.iPrecision, 10)); if (a2.iExp || a2.iTensExp) NormalizeFloat(a2, WordDigits(a2.iPrecision, 10)); // Two positive numbers BalanceFractions(a1, a2); if (!(a1.IsNegative() || a2.IsNegative())) { BaseAddFull(aResult, a1, a2); aResult.iNegative = false; } // Two negative numbers else if (a1.IsNegative() && a2.IsNegative()) { BaseAddFull(aResult, a1, a2); aResult.iNegative = true; } // Negative plus positive else if (a1.IsNegative() && !a2.IsNegative()) { // if |a1|<|a2| then BaseSubtract(a2,a1) if (BaseLessThan(a1, a2)) { BaseSubtract(aResult, a2, a1); aResult.iNegative = false; } else if (BaseGreaterThan(a1, a2)) { // else if (|a1| > |a2| // Negate(BaseSubtract(a1,a2)) BaseSubtract(aResult, a1, a2); aResult.iNegative = true; } else { ANumber zero(/*???"0",*/ aResult.iPrecision); aResult.CopyFrom(zero); } } // Positive plus Negative else { assert(!a1.IsNegative() && a2.IsNegative()); // if |a1|>|a2| then BaseSubtract(a2,a1) if (BaseGreaterThan(a1, a2)) { BaseSubtract(aResult, a1, a2); aResult.iNegative = false; } else if (BaseLessThan(a1, a2)) { // else if (|a1| > |a2| // Negate(BaseSubtract(a1,a2)) BaseSubtract(aResult, a2, a1); aResult.iNegative = true; } else { ANumber zero(/*???"0",*/ aResult.iPrecision); aResult.CopyFrom(zero); } } aResult.DropTrailZeroes(); if (aResult.iExp || aResult.iTensExp) { if (aResult.iPrecision < a2.iPrecision) aResult.iPrecision = a2.iPrecision; if (aResult.iPrecision < a1.iPrecision) aResult.iPrecision = a1.iPrecision; NormalizeFloat(aResult, WordDigits(aResult.iPrecision, 10)); } } // void Subtract(ANumber& aResult, ANumber& a1, ANumber& a2) // { // BalanceFractions(a1, a2); // if (!a1.IsNegative() && a2.IsNegative()) { // BaseAddFull(aResult, a1, a2); // aResult.iNegative = false; // } else if (a1.IsNegative() && !a2.IsNegative()) { // BaseAddFull(aResult, a1, a2); // aResult.iNegative = true; // } else if (a1.IsNegative() && a2.IsNegative()) { // // if |a1|<|a2| then BaseSubtract(a2,a1) // if (BaseLessThan(a1, a2)) { // BaseSubtract(aResult, a2, a1); // aResult.iNegative = false; // } else if (BaseGreaterThan(a1, a2)) { // else if (|a1| > |a2| // // Negate(BaseSubtract(a1,a2)) // BaseSubtract(aResult, a1, a2); // aResult.iNegative = true; // } else { // ANumber zero(/*???"0",*/ aResult.iPrecision); // aResult.CopyFrom(zero); // } // } // // Positive plus Negative // else { // assert(!(a1.IsNegative() || a2.IsNegative())); // // if |a1|>|a2| then BaseSubtract(a2,a1) // if (BaseGreaterThan(a1, a2)) { // BaseSubtract(aResult, a1, a2); // aResult.iNegative = false; // } else if (BaseLessThan(a1, a2)) { // else if (|a1| > |a2| // // Negate(BaseSubtract(a1,a2)) // BaseSubtract(aResult, a2, a1); // aResult.iNegative = true; // } else { // ANumber zero(/*???"0",*/ aResult.iPrecision); // aResult.CopyFrom(zero); // } // } // aResult.DropTrailZeroes(); // } bool GreaterThan(ANumber& a1, ANumber& a2) { BalanceFractions(a1, a2); if (a1.IsNegative() && !a2.IsNegative()) return false; if (!a1.IsNegative() && a2.IsNegative()) return true; if (!a1.IsNegative() && !a2.IsNegative()) return BaseGreaterThan(a1, a2); return BaseLessThan(a1, a2); } bool LessThan(ANumber& a1, ANumber& a2) { // if the numbers are float, make sure they are normalized if (a1.iExp || a1.iTensExp) NormalizeFloat(a1, WordDigits(a1.iPrecision, 10)); if (a2.iExp || a2.iTensExp) NormalizeFloat(a2, WordDigits(a2.iPrecision, 10)); BalanceFractions(a1, a2); if (a1.IsNegative() && !a2.IsNegative()) return true; if (!a1.IsNegative() && a2.IsNegative()) return false; if (!a1.IsNegative() && !a2.IsNegative()) return BaseLessThan(a1, a2); return BaseGreaterThan(a1, a2); } void ANumberToString(std::string& aResult, ANumber& aNumber, int aBase, bool aForceFloat) { while (aNumber.size() > 1 && aNumber.back() == 0) aNumber.pop_back(); std::size_t nr = aNumber.size(); // Formatting small numbers can be done faster. if (aNumber.iExp == 0 && nr == 1) { BaseIntNumber(aResult, aNumber[0], aBase); std::reverse(aResult.begin(), aResult.end()); std::transform(aResult.begin(), aResult.end(), aResult.begin(), &Digit); if (aForceFloat && !(aResult.size() == 1 && aResult[0] == '0')) aResult.push_back('.'); if (aNumber.iNegative && (aResult.size() > 1 || aResult[0] != '0')) aResult.insert(aResult.begin(), '-'); goto TENSEXP; } { ANumber number(aNumber.iPrecision); number.CopyFrom(aNumber); assert(aBase <= 36); // Reset number aResult.clear(); aResult.push_back(0); // Create the number std::string factor2; BaseIntNumber(factor2, 1, aBase); std::string factor3; BaseIntNumber(factor3, WordBase, aBase); assert(number.iExp >= 0); const std::size_t ns = number.size(); for (std::size_t i = number.iExp; i < ns; ++i) { // aResult = aResult + number[i] * factor2 std::string term; BaseIntNumber(term, number[i], aBase); BaseAddMultiply(aResult, term, factor2, aBase); // factor2 = factor2*factor3 term.swap(factor2); BaseMultiply(factor2, term, factor3, aBase); } // Remove trailing zeroes (most significant side) while (aResult.size() > 1 && aResult.back() == 0) aResult.pop_back(); std::reverse(aResult.begin(), aResult.end()); // Get the fraction number.resize(number.iExp, 0); if (aForceFloat || (number.iExp > 0 && !number.IsZero())) { int digitPos = aResult.size(); int i; // Build the fraction for (i = 0; i < number.iPrecision + 1; i++) { WordBaseTimesInt(number, aBase); if (int(number.size()) > number.iExp) { aResult.push_back(number[number.iExp]); number.resize(number.iExp); } else { aResult.push_back(0); } } // Round off if (aResult[aResult.size() - 1] >= (aBase >> 1)) { // TODO code bloat! int carry = 1; for (i = aResult.size() - 1; i >= 0; i--) { const int word = aResult[i] + carry; aResult[i] = word % aBase; carry = word / aBase; } if (carry) { aResult.insert(aResult.begin(), carry); digitPos++; } } aResult.resize(aResult.size() - 1); // Insert dot aResult.insert(aResult.begin() + digitPos, '.'); // Remove trailing zeros int nr = aResult.size(); while (nr > 1 && aResult[nr - 1] == 0) nr--; if (aResult[nr - 1] == '.' && nr == 2 && aResult[0] == 0) nr--; aResult.resize(nr); } // Map to ascii { LispString::value_type* rptr = &aResult[0]; const std::size_t nr = aResult.size(); for (std::size_t i = 0; i < nr; ++i) { *rptr = Digit(*rptr); rptr++; } } // If signed, insert a minus sign if (number.iNegative) if (aResult.size() > 1 || aResult[0] != '0') { char c = '-'; aResult.insert(aResult.begin(), c); } } // Handle tens exp TENSEXP: if (aNumber.iTensExp != 0 && !(aResult[0] == '0' && aResult.size() == 1)) { aResult.push_back('e'); aResult.append(std::to_string(aNumber.iTensExp)); } } void BaseAddFull(ANumber& aResult, ANumber& a1, ANumber& a2) { // Initialize result aResult.CopyFrom(a1); WordBaseAdd(aResult, a2); } void BaseSubtract(ANumber& aResult, ANumber& a1, ANumber& a2) { aResult.CopyFrom(a1); BaseSubtract(aResult, a2, 0); } void BaseMultiplyFull(ANumber& aResult, ANumber& a1, ANumber& a2) { // Initialize result WordBaseMultiply(aResult, a1, a2); } bool BaseGreaterThan(const ANumber& a1, const ANumber& a2) { const int nr1 = a1.size(); const int nr2 = a2.size(); // Nr is the number of words the two numbers share. const int nr = std::min(nr1, nr2); // Comparison of shared words. bool highSame; { int i = nr - 1; while (i > 0 && a1[i] == a2[i]) i--; highSame = (a1[i] > a2[i]); } // Two numbers with same numbers of words: compare these words. if (nr1 == nr2) return highSame; // a1 has more words. if (nr1 > nr2) { // If any of a1's higher words is non-zero, it will be bigger. int i; for (i = nr2; i < nr1; i++) if (a1[i] != 0) return true; // Otherwise compare the shared highest word. return highSame; } // If any of a2's higher words is non-zero, it will be bigger. int i; for (i = nr1; i < nr2; i++) if (a2[i] != 0) return false; // Otherwise compare the shared highest word. return highSame; } bool BaseLessThan(const ANumber& a1, const ANumber& a2) { return BaseGreaterThan(a2, a1); } void BaseShiftRight(ANumber& a, int aNrBits) { // Number of words a word jumps int wordsShifted = aNrBits / WordBits; // Residue: bits shifted out. int residue = aNrBits % WordBits; // Bit mask: bits that are going to be shifted out of each word. PlatDoubleWord bitMask = (PlatDoubleWord)((((PlatDoubleWord)1) << residue) - 1); // Nr of bits to move to the other side. int otherSideBits = WordBits - residue; int i; int nr = a.size(); ANumber::value_type* ptr = &a[0]; ANumber::value_type* ptrshifted = &a[wordsShifted]; ANumber::value_type* endp = ptr + nr - wordsShifted; if (ptr < endp) { *ptr = ((*ptrshifted) >> residue); ptr++; ptrshifted++; while (ptr < endp) // for (i=1;i> residue); ptr[-1] |= newCarry; ptr++; ptrshifted++; } } int start = nr - wordsShifted; if (start < 0) start = 0; for (i = start; i < nr; i++) { a[i] = 0; } } void BaseShiftLeft(ANumber& a, int aNrBits) { // Number of words a word jumps int wordsShifted = aNrBits / WordBits; // Residue: bits shifted out. int residue = aNrBits % WordBits; // Nr of bits to move to the other side. int otherSideBits = WordBits - residue; // Bit mask: bits that are going to be shifted out of each word. int bitMask = ((1L << residue) - 1) << otherSideBits; int i; int nr = a.size(); for (i = 0; i <= wordsShifted; i++) { a.push_back(0); } ANumber::value_type* ptr = &a[0]; for (i = nr + wordsShifted; i >= wordsShifted; i--) { PlatDoubleWord newCarry = (((PlatDoubleWord)ptr[i - wordsShifted]) & bitMask) >> otherSideBits; ptr[i] = (ptr[i - wordsShifted] << residue); if (i < nr + wordsShifted) ptr[i + 1] |= newCarry; } for (i = wordsShifted - 1; i >= 0; i--) { ptr[i] = 0; } } // /* Binary Greatest common divisor algorithm. */ // void BaseGcd(ANumber& aResult, ANumber& a1, ANumber& a2) // { // ANumber zero(aResult.Precision()); // ANumber u(aResult.Precision()); // ANumber v(aResult.Precision()); // u.CopyFrom(a1); // v.CopyFrom(a2); // u.iNegative = v.iNegative = false; // int k = 0; // { // int i = 0; // PlatWord bit = 1; // while (u[i] == 0 && v[i] == 0) // i++; // k += WordBits * i; // while ((u[i] & bit) == 0 && (v[i] & bit) == 0) { // bit <<= 1; // k++; // } // BaseShiftRight(u, k); // BaseShiftRight(v, k); // } // ANumber t(/*???"0",*/ 10); // if (!u.IsEven()) { // t.CopyFrom(v); // t.Negate(); // } else // t.CopyFrom(u); // while (!IsZero(t)) { // { // int k = 0; // int i = 0; // PlatWord bit = 1; // while (t[i] == 0) // i++; // k += WordBits * i; // while ((t[i] & bit) == 0) { // bit <<= 1; // k++; // } // BaseShiftRight(t, k); // } // if (GreaterThan(t, zero)) { // u.CopyFrom(t); // } else { // v.CopyFrom(t); // v.Negate(); // } // Subtract(t, u, v); // } // aResult.CopyFrom(u); // aResult.iNegative = false; // BaseShiftLeft(aResult, k); // } void BaseDivide(ANumber& aQuotient, ANumber& aRemainder, ANumber& a1, ANumber& a2) { // Find the values n and m as described in Knuth II: int n, m; n = a2.size(); assert(n > 0); assert(a2[n - 1] != 0); // a1.size() = m+n => m = a1.size()-n m = a1.size() - n; assert(m >= 0); aQuotient.resize(m + 1); // D1: PlatDoubleWord d = WordBase / (a2[n - 1] + 1); WordBaseTimesInt(a1, d); WordBaseTimesInt(a2, d); a1.push_back(0); a2.push_back(0); // D2: int j = m; while (j >= 0) { // D3: PlatDoubleWord q = (a1[j + n] * WordBase + a1[j + n - 1]) / a2[n - 1]; PlatDoubleWord r = (a1[j + n] * WordBase + a1[j + n - 1]) % a2[n - 1]; REDO: if (q == WordBase || q * a2[n - 2] > WordBase * r + a1[j + n - 2]) { q = q - 1; r = r + a2[n - 1]; if (r < WordBase) goto REDO; } // D4: ANumber sub(aQuotient.Precision()); sub.CopyFrom(a2); WordBaseTimesInt(sub, q); sub.push_back(0); PlatSignedDoubleWord carry; { // Subtract the two // TODO this can be generalized!!!! // // Beware though: this is not a normal subtraction. Only a // certain set of digits ends up being subtracted. // First check if qv isn't too big... carry = 0; for (int digit = 0; digit <= n; digit++) { PlatSignedDoubleWord word; word = ((PlatSignedDoubleWord)a1[digit + j]) - ((PlatSignedDoubleWord)sub[digit]) + (PlatSignedDoubleWord)carry; carry = 0; while (word < 0) { word += WordBase; carry--; } } if (carry) { q--; sub.CopyFrom(a2); WordBaseTimesInt(sub, q); sub.push_back(0); } carry = 0; for (int digit = 0; digit <= n; digit++) { PlatSignedDoubleWord word; word = ((PlatSignedDoubleWord)a1[digit + j]) - ((PlatSignedDoubleWord)sub[digit]) + (PlatSignedDoubleWord)carry; carry = 0; while (word < 0) { word += WordBase; carry--; } a1[digit + j] = ((PlatWord)(word)); } } assert(carry == 0); // D5: aQuotient[j] = (PlatWord)q; // D7: j--; } // D8: a1.resize(n); PlatDoubleWord carry; BaseDivideInt(a1, d, WordBase, carry); aRemainder.CopyFrom(a1); } void IntegerDivide(ANumber& aQuotient, ANumber& aRemainder, ANumber& a1, ANumber& a2) { assert(!a2.IsZero()); int n = a2.size(); while (a2[n - 1] == 0) n--; a2.resize(n); if (n == 1) { PlatDoubleWord carry; aQuotient.CopyFrom(a1); aQuotient.iExp = a1.iExp - a2.iExp; aQuotient.iTensExp = a1.iTensExp - a2.iTensExp; BaseDivideInt(aQuotient, a2[0], WordBase, carry); aRemainder.resize(1); aRemainder[0] = (PlatWord)carry; } // if |a1| < |a2| then result is zero. else if (BaseLessThan(a1, a2)) { aQuotient.iExp = 0; aQuotient.iTensExp = 0; aQuotient.resize(1); aQuotient[0] = 0; aRemainder.CopyFrom(a1); } else { aQuotient.iExp = a1.iExp - a2.iExp; aQuotient.iTensExp = a1.iTensExp - a2.iTensExp; // Divide the mantissas WordBaseDivide(aQuotient, aRemainder, a1, a2); } // Correct for signs if (a1.IsNegative() == a2.IsNegative()) { aQuotient.iNegative = false; aRemainder.iNegative = false; } else { aQuotient.iNegative = true; aRemainder.iNegative = true; } } void NormalizeFloat(ANumber& a2, int digitsNeeded) { if (a2.iExp - digitsNeeded > 0) { a2.erase(a2.begin(), a2.begin() + a2.iExp - digitsNeeded); a2.iExp -= (a2.iExp - digitsNeeded); } const std::size_t min = std::max(1 + digitsNeeded, a2.iExp + 1); std::size_t n = a2.size(); while (n > min || (n == min && a2.back() > 10)) { PlatDoubleWord carry = 0; BaseDivideInt(a2, 10, WordBase, carry); if (a2.back() == 0) a2.pop_back(); a2.iTensExp++; n = a2.size(); } } void Divide(ANumber& aQuotient, ANumber& aRemainder, ANumber& a1, ANumber& a2) { // Now add some digits to the front, to end up with the correct // precision: the resulting precision will be a1.iExp-a2.iExp. // This value should at least be WordDigits, so grow a1 // by WordDigits-(a1.iExp-a2.iExp) = WordDigits+a2.iExp-a1.iExp const int digitsNeeded = WordDigits(aQuotient.iPrecision, 10); NormalizeFloat(a2, digitsNeeded); const int toadd = a2.iExp - a1.iExp; PlatWord zero = 0; if (toadd > 0) { a1.insert(a1.begin(), toadd, zero); a1.iExp += toadd; } if (!a1.IsZero()) { const std::size_t n = a2.size(); while (a1.size() < n + digitsNeeded || a1.back() < a2.back()) { WordBaseTimesInt(a1, 10); a1.iTensExp--; } } IntegerDivide(aQuotient, aRemainder, a1, a2); NormalizeFloat(aQuotient, digitsNeeded); } // void BaseSqrt(ANumber& aResult, const ANumber& N) // { // int l2; // ANumber u(aResult.Precision()); // ANumber v(aResult.Precision()); // ANumber u2(aResult.Precision()); // ANumber v2(aResult.Precision()); // ANumber uv2(aResult.Precision()); // ANumber n(aResult.Precision()); // ANumber two("2", 10); // // sqrt(1) = 1, sqrt(0) = 0 // if (BaseGreaterThan(two, N)) { // aResult.CopyFrom(N); // return; // } // // Find highest set bit, l2 // u.CopyFrom(N); // l2 = 0; // while (!u.IsZero()) { // BaseShiftRight(u, 1); // l2++; // } // l2--; // // 1<<(l2/2) now would be a good under estimate for the square root. // // 1<<(l2/2) is definitely set in the result. Also it is the highest // // set bit. // l2 >>= 1; // // initialize u and u2 (u2==u^2). // u.SetTo("1"); // BaseShiftLeft(u, l2); // u2.CopyFrom(u); // BaseShiftLeft(u2, l2); // // Now for each lower bit: // while (l2--) { // // Get that bit in v, and v2 == v^2. // v.SetTo("1"); // BaseShiftLeft(v, l2); // v2.CopyFrom(v); // BaseShiftLeft(v2, l2); // // uv2 == 2*u*v // uv2.CopyFrom(u); // BaseShiftLeft(uv2, (l2 + 1)); // // n = (u+v)^2 = u^2 + 2*u*v + v^2 = u2+uv2+v2 // n.CopyFrom(u2); // WordBaseAdd(n, uv2); // WordBaseAdd(n, v2); // // if n (possible new best estimate for sqrt(N)^2 is smaller than // // N, then the bit l2 is set in the result, and add v to u. // if (!BaseGreaterThan(n, N)) { // WordBaseAdd(u, v); // u <- u+v // u2.CopyFrom(n); // u^2 <- u^2 + 2*u*v + v^2 // } // } // aResult.CopyFrom(u); // } // void Sqrt(ANumber& aResult, ANumber& N) // { // int digs = WordDigits(N.iPrecision, 10); // PlatWord zero = 0; // if ((N.iTensExp & 1) != 0) { // WordBaseTimesInt(N, 10); // N.iTensExp--; // } // while (N.iExp < 2 * digs || (N.iExp & 1)) { // N.insert(N.begin(), zero); // N.iExp++; // } // const int resultDigits = N.iExp / 2; // const int resultTensExp = N.iTensExp / 2; // BaseSqrt(aResult, N); // aResult.iExp = resultDigits; // aResult.iTensExp = resultTensExp; // } /*** Significant : return whether this number is not zero, up to * the number of digits specified behind the dot (as per aPrecision). */ bool Significant(ANumber& a) { int significantDigits = WordDigits(a.iPrecision, 10); NormalizeFloat(a, significantDigits); // hier int nrExt = (a.size() - a.iExp) * ((WordBits) / 3); if ((-a.iTensExp) > a.iPrecision + 2 + nrExt) { return false; } return true; } void ANumber::RoundBits() { PlatWord* ptr = data(); if (front() >= (WordBase / 2)) { PlatDoubleWord carry = 1; for (int i = 1, nr = size(); i < nr; i++) { const PlatDoubleWord dword = ptr[i] + carry; ptr[i] = dword; carry = dword >> WordBits; } if (carry) push_back(carry); } front() = 0; } void ANumber::ChangePrecision(int aPrecision) { // First, round. /*FIXME TODO not working correctly yet */ // TODO code bloat! Deserves its own routine! if (aPrecision == 0 && iExp > 1) { RoundBits(); } // return; // FIXME the following line is there to assure there are enough words. // Somehow this got truncated? // FIXME numerics.yts fails Expand(); int oldExp = iExp; iPrecision = aPrecision; int newExp = WordDigits(iPrecision, 10); if (newExp < oldExp) { iExp = newExp; erase(begin(), begin() + oldExp - iExp); } else if (newExp > oldExp) { iExp = newExp; PlatWord zero = 0; insert(begin(), newExp - oldExp, zero); } } void ANumber::DropTrailZeroes() { Expand(); { int nr = size(); while (nr > iExp + 1 && (*this)[nr - 1] == 0) nr--; resize(nr); } { int low = 0; while (low < iExp && (*this)[low] == 0) low++; if (low) { erase(begin(), begin() + low); iExp -= low; } } } ================================================ FILE: cyacas/libyacas/src/arggetter.cpp ================================================ #include "yacas/arggetter.h" #include "yacas/errors.h" #include "yacas/lispenvironment.h" #include "yacas/lispeval.h" #include "yacas/lispstring.h" #include "yacas/platmath.h" #include "yacas/standard.h" static const LispString* GetIntegerArgument(LispEnvironment& aEnvironment, int aStackTop, int aArgNr) { const LispString* str = aEnvironment.iStack[aStackTop + aArgNr]->String(); CheckArg(str, aArgNr, aEnvironment, aStackTop); CheckArg(IsNumber(*str, false), aArgNr, aEnvironment, aStackTop); return str; } int GetShortIntegerArgument(LispEnvironment& aEnvironment, int aStackTop, int aArgNr) { const LispString* str = GetIntegerArgument(aEnvironment, aStackTop, aArgNr); return InternalAsciiToInt(*str); } ================================================ FILE: cyacas/libyacas/src/associationclass.cpp ================================================ /* * Copyright (C) 2016 Grzegorz Mazur. * * Yacas is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "yacas/associationclass.h" LispPtr AssociationClass::Keys() const { LispPtr head(LispAtom::New(const_cast(_env), "List")); LispPtr p(head); for (std::map::const_reference e : _map) { p->Nixed() = e.first.value->Copy(); p = p->Nixed(); } return LispPtr(LispSubList::New(head)); } LispPtr AssociationClass::ToList() const { LispPtr head(LispAtom::New(const_cast(_env), "List")); LispPtr p(head); for (std::map::const_reference e : _map) { LispPtr q(LispAtom::New(const_cast(_env), "List")); p->Nixed() = LispSubList::New(q); p = p->Nixed(); q->Nixed() = e.first.value->Copy(); q = q->Nixed(); q->Nixed() = e.second->Copy(); } return LispPtr(LispSubList::New(head)); } LispPtr AssociationClass::Head() const { assert(_map.size()); std::map::const_reference e = *_map.begin(); LispPtr p(LispAtom::New(const_cast(_env), "List")); LispPtr q(p); q->Nixed() = e.first.value->Copy(); q = q->Nixed(); q->Nixed() = e.second->Copy(); return LispPtr(LispSubList::New(p)); } ================================================ FILE: cyacas/libyacas/src/deffile.cpp ================================================ #include "yacas/deffile.h" #include "yacas/lispenvironment.h" #include "yacas/lisperror.h" #include "yacas/lispio.h" #include "yacas/lispuserfunc.h" #include "yacas/platfileio.h" #include "yacas/standard.h" #include "yacas/stringio.h" #include "yacas/tokenizer.h" LispDefFile::LispDefFile(const std::string& aFileName) : iFileName(aFileName), iIsLoaded(false) { } void LispDefFile::SetLoaded() { iIsLoaded = true; } LispDefFile* LispDefFiles::File(const std::string& aFileName) { auto i = _map.find(aFileName); if (i == _map.end()) i = _map.emplace(aFileName, aFileName).first; return &i->second; } static void DoLoadDefFile(LispEnvironment& aEnvironment, LispInput* aInput, LispDefFile* def) { LispLocalInput localInput(aEnvironment, aInput); const LispString* eof = aEnvironment.iEndOfFile->String(); const LispString* end = aEnvironment.iListClose->String(); bool endoffile = false; LispTokenizer tok; while (!endoffile) { // Read expression const LispString* token = aEnvironment.HashTable().LookUp( tok.NextToken(*aEnvironment.CurrentInput())); // Check for end of file if (token == eof || token == end) { endoffile = true; } // Else evaluate else { LispMultiUserFunction* multiUser = aEnvironment.MultiUserFunction(token); if (multiUser->iFileToOpen != nullptr) { aEnvironment.CurrentOutput() << '[' << *token << "]\n"; if (multiUser->iFileToOpen) throw LispErrDefFileAlreadyChosen(); } multiUser->iFileToOpen = def; def->symbols.insert(token); aEnvironment.Protect(token); } } } void LoadDefFile(LispEnvironment& aEnvironment, const std::string& aFileName) { const std::string flatfile = InternalUnstringify(aFileName) + ".def"; LispDefFile* def = aEnvironment.DefFiles().File(aFileName); InputStatus oldstatus = aEnvironment.iInputStatus; aEnvironment.iInputStatus.SetTo(flatfile); LispLocalFile localFP( aEnvironment, flatfile, true, aEnvironment.iInputDirectories); if (!localFP.stream.is_open()) throw LispErrFileNotFound(); StdFileInput newInput(localFP, aEnvironment.iInputStatus); DoLoadDefFile(aEnvironment, &newInput, def); aEnvironment.iInputStatus.RestoreFrom(oldstatus); } ================================================ FILE: cyacas/libyacas/src/errors.cpp ================================================ #include "yacas/errors.h" #include "yacas/infixparser.h" #include "yacas/lispenvironment.h" #include "yacas/lispeval.h" #include "yacas/standard.h" void ShowStack(LispEnvironment& aEnvironment) { aEnvironment.iEvaluator->ShowStack(aEnvironment, aEnvironment.iErrorOutput); } void ShowFunctionError(LispPtr& aArguments, LispEnvironment& aEnvironment) { if (const LispString* string = aArguments->String()) aEnvironment.iErrorOutput << "In function \"" << *string << "\" : \n"; } void ShowArgTypeErrorInfo(int aArgNr, LispPtr& aArguments, LispEnvironment& aEnvironment) { ShowStack(aEnvironment); ShowFunctionError(aArguments, aEnvironment); aEnvironment.iErrorOutput << "bad argument number " << aArgNr << " (counting from 1)\n"; const int LIM_AL = 60; LispPtr& arg = Argument(aArguments, aArgNr); LispString strout; PrintExpression(strout, arg, aEnvironment, LIM_AL); aEnvironment.iErrorOutput << "The offending argument " << strout; LispPtr eval; aEnvironment.iEvaluator->Eval(aEnvironment, eval, arg); PrintExpression(strout, eval, aEnvironment, LIM_AL); aEnvironment.iErrorOutput << " evaluated to " << strout << '\n'; } void CheckArg(bool pred, int arg_idx, LispEnvironment& env, int stack_top) { if (!pred) { ShowArgTypeErrorInfo(arg_idx, env.iStack[stack_top], env); throw LispErrInvalidArg(); } } void CheckArgIsString(LispPtr arg, int arg_idx, LispEnvironment& env, int stack_top) { if (!InternalIsString(arg->String())) { ShowArgTypeErrorInfo(arg_idx, env.iStack[stack_top], env); throw LispErrNotString(); } } void CheckArgIsString(int arg_idx, LispEnvironment& env, int stack_top) { CheckArgIsString(env.iStack[stack_top + arg_idx], arg_idx, env, stack_top); } void CheckArgIsList(LispPtr arg, int arg_idx, LispEnvironment& env, int stack_top) { if (!InternalIsList(env, arg)) { ShowArgTypeErrorInfo(arg_idx, env.iStack[stack_top], env); throw LispErrNotList(); } } void CheckArgIsList(int arg_idx, LispEnvironment& env, int stack_top) { CheckArgIsList(env.iStack[stack_top + arg_idx], arg_idx, env, stack_top); } void CheckNrArgs(int n, LispPtr& aArguments, LispEnvironment& aEnvironment) { const int nrArguments = InternalListLength(aArguments); if (nrArguments == n) return; const int needed = n - 1; const int passed = nrArguments - 1; ShowStack(aEnvironment); ShowFunctionError(aArguments, aEnvironment); aEnvironment.iErrorOutput << "expected " << needed << " arguments, got " << passed << "\n"; throw LispErrWrongNumberOfArgs(); } void CheckSecure(LispEnvironment& env, int stack_top) { if (env.secure) { ShowStack(env); ShowFunctionError(env.iStack[stack_top], env); throw LispErrSecurityBreach(); } } ================================================ FILE: cyacas/libyacas/src/infixparser.cpp ================================================ #include "yacas/infixparser.h" #include "yacas/arrayclass.h" #include "yacas/associationclass.h" #include "yacas/errors.h" #include "yacas/lispatom.h" #include "yacas/lisperror.h" #include "yacas/standard.h" #include #include void ParsedObject::Fail() { if (iLookAhead && !iLookAhead->empty()) throw LispErrInvalidExpression(*iLookAhead); throw LispErrInvalidExpression(); } InfixParser::InfixParser(LispTokenizer& aTokenizer, LispInput& aInput, LispEnvironment& aEnvironment, LispOperators& aPrefixOperators, LispOperators& aInfixOperators, LispOperators& aPostfixOperators, LispOperators& aBodiedOperators) : LispParser(aTokenizer, aInput, aEnvironment), iPrefixOperators(aPrefixOperators), iInfixOperators(aInfixOperators), iPostfixOperators(aPostfixOperators), iBodiedOperators(aBodiedOperators) { } void InfixParser::Parse(LispPtr& aResult) { ParseCont(aResult); } void InfixParser::ParseCont(LispPtr& aResult) { ParsedObject object(*this); object.Parse(); aResult = object.iResult; } void ParsedObject::ReadToken() { // Get token. iLookAhead = iParser.iEnvironment.HashTable().LookUp( iParser.iTokenizer.NextToken(iParser.iInput)); if (iLookAhead->empty()) iEndOfFile = true; } void ParsedObject::MatchToken(const LispString* aToken) { if (aToken != iLookAhead) Fail(); ReadToken(); } void ParsedObject::Parse() { ReadToken(); if (iEndOfFile) { iResult = (iParser.iEnvironment.iEndOfFile->Copy()); return; } ReadExpression(KMaxPrecedence); // least precedence if (iLookAhead != iParser.iEnvironment.iEndStatement->String()) Fail(); } void ParsedObject::Combine(int aNrArgsToCombine) { LispPtr subList(LispSubList::New(iResult)); // TODO: woof -- such ugliness! LispIterator iter(iResult); for (int i = 0; i < aNrArgsToCombine; i++, ++iter) if (!iter.getObj()) Fail(); if (!iter.getObj()) Fail(); subList->Nixed() = *++iter; *iter = nullptr; InternalReverseList((*subList->SubList())->Nixed(), // TODO: woof (*subList->SubList())->Nixed()); iResult = subList; } void ParsedObject::GetOtherSide(int aNrArgsToCombine, int depth) { const LispString* theOperator = iLookAhead; MatchToken(iLookAhead); ReadExpression(depth); InsertAtom(theOperator); Combine(aNrArgsToCombine); } void ParsedObject::InsertAtom(const LispString* aString) { LispPtr ptr(LispAtom::New(iParser.iEnvironment, *aString)); ptr->Nixed() = iResult; iResult = ptr; } void ParsedObject::ReadExpression(int depth) { ReadAtom(); for (;;) { // Handle special case: a[b]. a is matched with lowest precedence!! if (iLookAhead == iParser.iEnvironment.iProgOpen->String()) { // Match opening bracket MatchToken(iLookAhead); // Read "index" argument ReadExpression(KMaxPrecedence); // Match closing bracket if (iLookAhead != iParser.iEnvironment.iProgClose->String()) throw LispErrGeneric( std::string("Expecting a ] close bracket for program " "block, but got ") + *iLookAhead + std::string(" instead")); MatchToken(iLookAhead); // Build into Ntn(...) const LispString* theOperator = iParser.iEnvironment.iNth->String(); InsertAtom(theOperator); Combine(2); } else { LispOperators::const_iterator opi = iParser.iInfixOperators.find(iLookAhead); if (opi == iParser.iInfixOperators.end()) { if (!IsSymbolic((*iLookAhead)[0])) return; const std::size_t origlen = iLookAhead->size(); std::size_t len = origlen; while (len > 1) { len -= 1; const LispString* lookUp = iParser.iEnvironment.HashTable().LookUp( iLookAhead->substr(0, len)); opi = iParser.iInfixOperators.find(lookUp); if (opi != iParser.iInfixOperators.end()) { const LispString* lookUpRight = iParser.iEnvironment.HashTable().LookUp( iLookAhead->substr(len, origlen - len)); if (iParser.iPrefixOperators.find(lookUpRight) != iParser.iPrefixOperators.end()) { iLookAhead = lookUp; LispInput& input = iParser.iInput; std::size_t newPos = input.Position() - (origlen - len); input.SetPosition(newPos); break; } opi = iParser.iInfixOperators.end(); } } if (opi == iParser.iInfixOperators.end()) return; } if (depth < opi->second.iPrecedence) return; int upper = opi->second.iPrecedence; if (!opi->second.iRightAssociative) upper--; GetOtherSide(2, upper); } } } void ParsedObject::ReadAtom() { LispOperators::const_iterator opi = iParser.iPrefixOperators.find(iLookAhead); if (opi != iParser.iPrefixOperators.end()) { const LispString* theOperator = iLookAhead; MatchToken(iLookAhead); { ReadExpression(opi->second.iPrecedence); InsertAtom(theOperator); Combine(1); } } // Else parse brackets else if (iLookAhead == iParser.iEnvironment.iBracketOpen->String()) { MatchToken(iLookAhead); ReadExpression(KMaxPrecedence); // least precedence MatchToken(iParser.iEnvironment.iBracketClose->String()); } // Parse lists else if (iLookAhead == iParser.iEnvironment.iListOpen->String()) { int nrargs = 0; MatchToken(iLookAhead); while (iLookAhead != iParser.iEnvironment.iListClose->String()) { ReadExpression(KMaxPrecedence); // least precedence nrargs++; if (iLookAhead == iParser.iEnvironment.iComma->String()) { MatchToken(iLookAhead); } else if (iLookAhead != iParser.iEnvironment.iListClose->String()) { throw LispErrGeneric( std::string("Expecting a } close bracket for program " "block, but got ") + *iLookAhead + std::string(" instead")); } } MatchToken(iLookAhead); const LispString* theOperator = iParser.iEnvironment.iList->String(); InsertAtom(theOperator); Combine(nrargs); } // Parse prog bodies else if (iLookAhead == iParser.iEnvironment.iProgOpen->String()) { int nrargs = 0; MatchToken(iLookAhead); while (iLookAhead != iParser.iEnvironment.iProgClose->String()) { ReadExpression(KMaxPrecedence); // least precedence nrargs++; if (iLookAhead == iParser.iEnvironment.iEndStatement->String()) { MatchToken(iLookAhead); } else { throw LispErrGeneric(std::string("Expecting ; end of statement " "in program block, but got ") + *iLookAhead + std::string(" instead")); } } MatchToken(iLookAhead); const LispString* theOperator = iParser.iEnvironment.iProg->String(); InsertAtom(theOperator); Combine(nrargs); } // Else we have an atom. else { const LispString* theOperator = iLookAhead; MatchToken(iLookAhead); int nrargs = -1; if (iLookAhead == iParser.iEnvironment.iBracketOpen->String()) { nrargs = 0; MatchToken(iLookAhead); while (iLookAhead != iParser.iEnvironment.iBracketClose->String()) { ReadExpression(KMaxPrecedence); // least precedence nrargs++; if (iLookAhead == iParser.iEnvironment.iComma->String()) { MatchToken(iLookAhead); } else if (iLookAhead != iParser.iEnvironment.iBracketClose->String()) { throw LispErrGeneric( std::string("Expecting a ) closing bracket for " "sub-expression, but got ") + *iLookAhead + std::string(" instead")); } } MatchToken(iLookAhead); opi = iParser.iBodiedOperators.find(theOperator); if (opi != iParser.iBodiedOperators.end()) { ReadExpression(opi->second.iPrecedence); // KMaxPrecedence nrargs++; } } InsertAtom(theOperator); if (nrargs >= 0) Combine(nrargs); } // Parse postfix operators while (iParser.iPostfixOperators.find(iLookAhead) != iParser.iPostfixOperators.end()) { InsertAtom(iLookAhead); MatchToken(iLookAhead); Combine(1); } } void InfixPrinter::WriteToken(std::ostream& aOutput, const std::string& aString) { if (IsAlNum(iPrevLastChar) && (IsAlNum(aString[0]) || aString[0] == '_')) aOutput.put(' '); else if (IsSymbolic(iPrevLastChar) && IsSymbolic(aString[0])) aOutput.put(' '); aOutput.write(aString.c_str(), aString.size()); RememberLastChar(aString.back()); } void InfixPrinter::RememberLastChar(char aChar) { iPrevLastChar = aChar; } void InfixPrinter::Print(const LispPtr& aExpression, std::ostream& aOutput, LispEnvironment& aEnvironment) { iCurrentEnvironment = &aEnvironment; Print(aExpression, aOutput, KMaxPrecedence); } void InfixPrinter::Print(const LispPtr& aExpression, std::ostream& aOutput, int iPrecedence) { assert(aExpression); const LispString* string = aExpression->String(); if (string) { int bracket = 0; if (iPrecedence < KMaxPrecedence && (*string)[0] == '-' && (std::isdigit((*string)[1]) || (*string)[1] == '.')) { bracket = 1; } if (bracket) WriteToken(aOutput, "("); WriteToken(aOutput, *string); if (bracket) WriteToken(aOutput, ")"); return; } if (const GenericClass* g = aExpression->Generic()) { if (const AssociationClass* a = dynamic_cast(g)) { WriteToken(aOutput, "Association"); WriteToken(aOutput, "("); Print(a->ToList(), aOutput, KMaxPrecedence); WriteToken(aOutput, ")"); } else if (const ArrayClass* a = dynamic_cast(g)) { WriteToken(aOutput, "Array"); WriteToken(aOutput, "("); WriteToken(aOutput, "{"); const std::size_t n = a->Size(); for (std::size_t i = 1; i <= n; ++i) { Print(LispPtr(a->GetElement(i)), aOutput, KMaxPrecedence); if (i != n) WriteToken(aOutput, ","); } WriteToken(aOutput, "}"); WriteToken(aOutput, ")"); } else { WriteToken(aOutput, g->TypeName()); } return; } LispPtr* subList = aExpression->SubList(); if (!subList) { throw LispErrUnprintableToken(); } else { const std::size_t length = InternalListLength(*subList); string = (*subList)->String(); const LispOperators::const_iterator prefix = length != 2 ? iPrefixOperators.end() : iPrefixOperators.find(string); const LispOperators::const_iterator infix = length != 3 ? iInfixOperators.end() : iInfixOperators.find(string); const LispOperators::const_iterator postfix = length != 2 ? iPostfixOperators.end() : iPostfixOperators.find(string); const LispOperators::const_iterator bodied = iBodiedOperators.find(string); const LispInFixOperator* op = nullptr; if (prefix != iPrefixOperators.end()) op = &prefix->second; if (postfix != iPostfixOperators.end()) op = &postfix->second; if (infix != iInfixOperators.end()) op = &infix->second; if (op) { LispPtr* left = nullptr; LispPtr* right = nullptr; if (prefix != iPrefixOperators.end()) { right = &(*subList)->Nixed(); } else if (infix != iInfixOperators.end()) { left = &(*subList)->Nixed(); right = &(*subList)->Nixed()->Nixed(); } else if (postfix != iPostfixOperators.end()) { left = &(*subList)->Nixed(); } if (iPrecedence < op->iPrecedence) { WriteToken(aOutput, "("); } else { // Vladimir? aOutput.Write(" "); } if (left) Print(*left, aOutput, op->iLeftPrecedence); WriteToken(aOutput, *string); if (right) Print(*right, aOutput, op->iRightPrecedence); if (iPrecedence < op->iPrecedence) WriteToken(aOutput, ")"); } else { LispIterator iter((*subList)->Nixed()); if (string == iCurrentEnvironment->iList->String()) { WriteToken(aOutput, "{"); for (int ii = 0; iter.getObj(); ii++, ++iter) { if (ii) WriteToken(aOutput, ","); Print(*iter, aOutput, KMaxPrecedence); } WriteToken(aOutput, "}"); } else if (string == iCurrentEnvironment->iProg->String()) { WriteToken(aOutput, "["); while (iter.getObj()) { Print(*iter, aOutput, KMaxPrecedence); ++iter; WriteToken(aOutput, ";"); } WriteToken(aOutput, "]"); } else if (string == iCurrentEnvironment->iNth->String()) { Print(*iter, aOutput, 0); ++iter; WriteToken(aOutput, "["); Print(*iter, aOutput, KMaxPrecedence); WriteToken(aOutput, "]"); } else { int bracket = false; if (bodied != iBodiedOperators.end()) { // printf("%d > %d\n",iPrecedence, bodied->iPrecedence); if (iPrecedence < bodied->second.iPrecedence) bracket = true; } if (bracket) WriteToken(aOutput, "("); if (string) { WriteToken(aOutput, *string); } else { Print(*subList, aOutput, 0); } WriteToken(aOutput, "("); LispIterator counter(*iter); int nr = 0; while (counter.getObj()) { ++counter; nr++; } if (bodied != iBodiedOperators.end()) nr--; while (nr--) { Print(*iter, aOutput, KMaxPrecedence); ++iter; if (nr) WriteToken(aOutput, ","); } WriteToken(aOutput, ")"); if (iter.getObj()) { assert(bodied != iBodiedOperators.end()); Print(*iter, aOutput, bodied->second.iPrecedence); } if (bracket) WriteToken(aOutput, ")"); } } } } ================================================ FILE: cyacas/libyacas/src/lispatom.cpp ================================================ #include "yacas/lispatom.h" #include "yacas/lisperror.h" #include "yacas/numbers.h" #include "yacas/standard.h" #include #include /// construct an atom from a string representation. LispObject* LispAtom::New(LispEnvironment& aEnvironment, const std::string& aString) { if (IsNumber(aString, true)) // check if aString is a number (int or float) return new LispNumber(new LispString(aString), aEnvironment.Precision()); return new LispAtom(aEnvironment.HashTable().LookUp(aString)); } LispAtom::LispAtom(const LispString* aString) : iString(aString) { assert(aString); } const LispString* LispAtom::String() { assert(iString); return iString; } //------------------------------------------------------------------------------ // LispSublist methods LispSubList* LispSubList::New(LispObject* aSubList) { return new LispSubList(aSubList); } // A destructor for lists that is less taxing for stacks :-) // Eg. deleting a list deletes the entire sublist also, in // a tail-recursive way... LispSubList::~LispSubList() { if (!!iSubList) { LispPtr next; LispIterator iter(iSubList); bool busy = (iter.getObj()->use_count() == 1); while (busy) // while there are things to delete... { // TODO: woof -- fix this ugliness! LispPtr nextToDelete; // Make sure "next" holds the tail of the list nextToDelete = (iter.getObj()->Nixed()); // Separate out the current element... if (iter.getObj()->use_count() == 1) { // Destructive operation only if necessary... iter.getObj()->Nixed() = (nullptr); // And delete it. (*iter) = (nullptr); } else busy = false; next = (nextToDelete); iter = next; if (!iter.getObj()) busy = false; } } } //------------------------------------------------------------------------------ // LispGenericClass methods LispGenericClass* LispGenericClass::New(GenericClass* aClass) { return new LispGenericClass(aClass); } LispGenericClass::LispGenericClass(GenericClass* aClass) : iClass(aClass) { assert(aClass != nullptr); aClass->iReferenceCount++; } LispGenericClass::~LispGenericClass() { if (--iClass->iReferenceCount == 0) delete iClass; } GenericClass* LispGenericClass::Generic() { return iClass; } //------------------------------------------------------------------------------ // LispNumber methods - proceed at your own risk /// return a string representation in decimal LispString* LispNumber::String() { if (!iString) { assert( iNumber .ptr()); // either the string is null or the number but not both LispString* str = new LispString; // export the current number to string and store it as // LispNumber::iString iNumber->ToString( *str, bits_to_digits(std::max(1, iNumber->GetPrecision()), BASE10), BASE10); iString = str; } return iString; } /// Return a BigNumber object. // Will create a BigNumber object out of a stored string, at given precision (in // decimal) - that's why the aPrecision argument must be here - but only if no // BigNumber object is already present BigNumber* LispNumber::Number(int aBasePrecision) { if (!iNumber) { // create and store a BigNumber out of string assert(iString.ptr()); // aBasePrecision is in digits, not in bits, ok iNumber = new BigNumber(*iString, aBasePrecision, BASE10); } // check if the BigNumber object has enough precision, if not, extend it // (applies only to floats). Note that iNumber->GetPrecision() might be < 0 else if (!iNumber->IsInt() && iNumber->GetPrecision() < (int)digits_to_bits(aBasePrecision, BASE10)) { if (iString) // have string representation, can extend precision iNumber = new BigNumber(*iString, aBasePrecision, BASE10); } return iNumber; } ================================================ FILE: cyacas/libyacas/src/lispenvironment.cpp ================================================ #include "yacas/lispenvironment.h" #include "yacas/errors.h" #include "yacas/lispatom.h" #include "yacas/lispeval.h" #include "yacas/lispuserfunc.h" #include "yacas/mathuserfunc.h" #include "yacas/standard.h" // we need this only for digits_to_bits #include "yacas/numbers.h" LispEnvironment::LispEnvironment(YacasCoreCommands& aCoreCommands, LispUserFunctions& aUserFunctions, LispGlobal& aGlobals, LispHashTable& aHashTable, std::ostream& aOutput, LispPrinter& aPrinter, LispOperators& aPreFixOperators, LispOperators& aInFixOperators, LispOperators& aPostFixOperators, LispOperators& aBodiedOperators, LispIdentifiers& protected_symbols, LispInput* aCurrentInput) : iPrecision(10), // default user precision of 10 decimal digits iBinaryPrecision(34), // same as 34 bits iInputDirectories(), // iCleanup(), iEvalDepth(0), iMaxEvalDepth(1000), stop_evaluation(false), iEvaluator(new BasicEvaluator), iInputStatus(), secure(false), iTrue(), iFalse(), iEndOfFile(), iEndStatement(), iProgOpen(), iProgClose(), iNth(), iBracketOpen(), iBracketClose(), iListOpen(), iListClose(), iComma(), iList(), iProg(), iLastUniqueId(1), iDebugger(nullptr), iInitialOutput(&aOutput), iCoreCommands(aCoreCommands), iUserFunctions(aUserFunctions), iHashTable(aHashTable), iDefFiles(), iPrinter(aPrinter), iCurrentOutput(&aOutput), iGlobals(aGlobals), iPreFixOperators(aPreFixOperators), iInFixOperators(aInFixOperators), iPostFixOperators(aPostFixOperators), iBodiedOperators(aBodiedOperators), protected_symbols(protected_symbols), iCurrentInput(aCurrentInput), iPrettyReader(nullptr), iPrettyPrinter(nullptr), iDefaultTokenizer(), iXmlTokenizer(), iCurrentTokenizer(&iDefaultTokenizer) { iTrue = LispAtom::New(*this, "True"); iFalse = LispAtom::New(*this, "False"); Protect(iTrue->String()); Protect(iFalse->String()); iEndOfFile = LispAtom::New(*this, "EndOfFile"); iEndStatement = LispAtom::New(*this, ";"); iProgOpen = LispAtom::New(*this, "["); iProgClose = LispAtom::New(*this, "]"); iNth = LispAtom::New(*this, "Nth"); iBracketOpen = LispAtom::New(*this, "("); iBracketClose = LispAtom::New(*this, ")"); iListOpen = LispAtom::New(*this, "{"); iListClose = LispAtom::New(*this, "}"); iComma = LispAtom::New(*this, ","); iList = LispAtom::New(*this, "List"); iProg = LispAtom::New(*this, "Prog"); Protect(iList->String()); Protect(iProg->String()); Protect(iHashTable.LookUp("Infinity")); Protect(iHashTable.LookUp("Undefined")); PushLocalFrame(true); } LispEnvironment::~LispEnvironment() { delete iEvaluator; delete iDebugger; } void LispEnvironment::SetPrecision(int aPrecision) { iPrecision = aPrecision; // precision in decimal digits iBinaryPrecision = digits_to_bits(aPrecision, BASE10); // in bits } int LispEnvironment::GetUniqueId() { return iLastUniqueId++; } LispPtr* LispEnvironment::FindLocal(const LispString* aVariable) { assert(!_local_frames.empty()); std::size_t last = _local_vars.size(); for (std::vector::const_reverse_iterator f = _local_frames.rbegin(); f != _local_frames.rend(); ++f) { const std::size_t first = f->first; for (std::size_t i = last; i > first; --i) if (_local_vars[i - 1].var == aVariable) return &_local_vars[i - 1].val; if (f->fenced) break; last = first; } return nullptr; } void LispEnvironment::SetVariable(const LispString* aVariable, LispPtr& aValue, bool aGlobalLazyVariable) { if (LispPtr* local = FindLocal(aVariable)) { *local = aValue; return; } // FIXME: or should local variables be protected as well? if (Protected(aVariable)) throw LispErrProtectedSymbol(*aVariable); auto i = iGlobals.find(aVariable); if (i != iGlobals.end()) i->second = LispGlobalVariable(aValue); else i = iGlobals .insert(std::make_pair(aVariable, LispGlobalVariable(aValue))) .first; if (aGlobalLazyVariable) i->second.SetEvalBeforeReturn(true); } void LispEnvironment::GetVariable(const LispString* aVariable, LispPtr& aResult) { aResult = nullptr; if (LispPtr* local = FindLocal(aVariable)) { aResult = *local; return; } auto i = iGlobals.find(aVariable); if (i != iGlobals.end()) { LispGlobalVariable* l = &i->second; if (l->iEvalBeforeReturn) { iEvaluator->Eval(*this, aResult, l->iValue); // re-lookup the global variable, as this pointer might now be // invalid due to the evaluation actually changing the global // itself. l = &iGlobals.find(aVariable)->second; l->iValue = aResult; l->iEvalBeforeReturn = false; } else { aResult = l->iValue; } } } void LispEnvironment::UnsetVariable(const LispString* var) { if (LispPtr* local = FindLocal(var)) *local = nullptr; else { // FIXME: or should local variables be protected as well? if (Protected(var)) throw LispErrProtectedSymbol(*var); iGlobals.erase(var); } } void LispEnvironment::PushLocalFrame(bool fenced) { _local_frames.emplace_back(_local_vars.size(), fenced); } void LispEnvironment::PopLocalFrame() { assert(!_local_frames.empty()); _local_vars.erase(_local_vars.begin() + _local_frames.back().first, _local_vars.end()); _local_frames.pop_back(); } void LispEnvironment::NewLocal(const LispString* var, LispObject* val) { assert(!_local_frames.empty()); _local_vars.emplace_back(var, val); } void LispEnvironment::CurrentLocals(LispPtr& aResult) { assert(!_local_frames.empty()); LispObject* locals = nullptr; std::size_t last = _local_vars.size(); for (std::vector::const_reverse_iterator f = _local_frames.rbegin(); f != _local_frames.rend(); ++f) { const std::size_t first = f->first; for (std::size_t i = last; i > first; --i) locals = LispObjectAdder(LispAtom::New(*this, *_local_vars[i - 1].var)) + LispObjectAdder(locals); if (f->fenced) break; last = first; } aResult = LispSubList::New(LispObjectAdder(iList->Copy()) + LispObjectAdder(locals)); } void LispEnvironment::GlobalVariables(LispPtr& aResult) { LispPtr vars(iList->Copy()); LispIterator tail(vars); ++tail; for (const auto& p: iGlobals) { if (p.first->front() == '$' || p.first->front() == '%') continue; *tail = LispAtom::New(*this, *p.first); ++tail; } aResult = LispSubList::New(vars); } LispPrinter& LispEnvironment::CurrentPrinter() { return iPrinter; } LispDefFiles& LispEnvironment::DefFiles() { return iDefFiles; } LispOperators& LispEnvironment::PreFix() { return iPreFixOperators; } LispOperators& LispEnvironment::InFix() { return iInFixOperators; } LispOperators& LispEnvironment::PostFix() { return iPostFixOperators; } LispOperators& LispEnvironment::Bodied() { return iBodiedOperators; } LispInput* LispEnvironment::CurrentInput() { return iCurrentInput; } void LispEnvironment::SetCurrentInput(LispInput* aInput) { iCurrentInput = aInput; } std::ostream& LispEnvironment::CurrentOutput() { return *iCurrentOutput; } void LispEnvironment::SetCurrentOutput(std::ostream& aOutput) { iCurrentOutput = &aOutput; } LispUserFunction* LispEnvironment::UserFunction(LispPtr& aArguments) { auto i = iUserFunctions.find(aArguments->String()); if (i != iUserFunctions.end()) { LispMultiUserFunction* multiUserFunc = &i->second; int arity = InternalListLength(aArguments) - 1; return multiUserFunc->UserFunc(arity); } return nullptr; } LispUserFunction* LispEnvironment::UserFunction(const LispString* aName, int aArity) { auto i = iUserFunctions.find(aName); if (i != iUserFunctions.end()) return i->second.UserFunc(aArity); return nullptr; } void LispEnvironment::UnFenceRule(const LispString* aOperator, int aArity) { if (Protected(aOperator)) throw LispErrProtectedSymbol(*aOperator); auto i = iUserFunctions.find(aOperator); if (i == iUserFunctions.end()) throw LispErrInvalidArg(); LispMultiUserFunction* multiUserFunc = &i->second; LispUserFunction* userFunc = multiUserFunc->UserFunc(aArity); if (!userFunc) throw LispErrInvalidArg(); userFunc->UnFence(); } void LispEnvironment::Retract(const LispString* aOperator, int aArity) { if (Protected(aOperator)) throw LispErrProtectedSymbol(*aOperator); auto i = iUserFunctions.find(aOperator); if (i != iUserFunctions.end()) i->second.DeleteBase(aArity); } void LispEnvironment::DeclareRuleBase(const LispString* aOperator, LispPtr& aParameters, int aListed) { if (Protected(aOperator)) throw LispErrProtectedSymbol(*aOperator); LispMultiUserFunction* multiUserFunc = MultiUserFunction(aOperator); /* if (multiUserFunc->iFileToOpen) { LISPASSERT(multiUserFunc->iFileToOpen->iIsLoaded); } */ // add an operator with this arity to the multiuserfunc. BranchingUserFunction* newFunc = aListed ? new ListedBranchingUserFunction(aParameters) : new BranchingUserFunction(aParameters); multiUserFunc->DefineRuleBase(newFunc); } void LispEnvironment::DeclareMacroRuleBase(const LispString* aOperator, LispPtr& aParameters, int aListed) { if (Protected(aOperator)) throw LispErrProtectedSymbol(*aOperator); LispMultiUserFunction* multiUserFunc = MultiUserFunction(aOperator); MacroUserFunction* newFunc = aListed ? new ListedMacroUserFunction(aParameters) : new MacroUserFunction(aParameters); multiUserFunc->DefineRuleBase(newFunc); } LispMultiUserFunction* LispEnvironment::MultiUserFunction(const LispString* aOperator) { auto i = iUserFunctions.find(aOperator); if (i != iUserFunctions.end()) return &i->second; LispMultiUserFunction newMulti; return &iUserFunctions.insert(std::make_pair(aOperator, newMulti)) .first->second; } void LispEnvironment::HoldArgument(const LispString* aOperator, const LispString* aVariable) { auto i = iUserFunctions.find(aOperator); if (i == iUserFunctions.end()) throw LispErrInvalidArg(); LispMultiUserFunction* multiUserFunc = &i->second; multiUserFunc->HoldArgument(aVariable); } void LispEnvironment::Protect(const LispString* symbol) { protected_symbols.insert(symbol); } void LispEnvironment::UnProtect(const LispString* symbol) { protected_symbols.erase(symbol); } bool LispEnvironment::Protected(const LispString* symbol) const { return protected_symbols.find(symbol) != protected_symbols.end(); } void LispEnvironment::DefineRule(const LispString* aOperator, int aArity, int aPrecedence, LispPtr& aPredicate, LispPtr& aBody) { if (Protected(aOperator)) throw LispErrProtectedSymbol(*aOperator); // Find existing multiuser func. auto i = iUserFunctions.find(aOperator); if (i == iUserFunctions.end()) throw LispErrCreatingRule(); LispMultiUserFunction* multiUserFunc = &i->second; // Get the specific user function with the right arity LispUserFunction* userFunc = multiUserFunc->UserFunc(aArity); if (!userFunc) throw LispErrCreatingRule(); // Declare a new evaluation rule if (IsTrue(*this, aPredicate)) { // printf("FastPredicate on %s\n",aOperator->String()); userFunc->DeclareRule(aPrecedence, aBody); } else userFunc->DeclareRule(aPrecedence, aPredicate, aBody); } void LispEnvironment::DefineRulePattern(const LispString* aOperator, int aArity, int aPrecedence, LispPtr& aPredicate, LispPtr& aBody) { // if (Protected(aOperator)) // throw LispErrProtectedSymbol(*aOperator); // Find existing multiuser func. auto i = iUserFunctions.find(aOperator); if (i == iUserFunctions.end()) throw LispErrCreatingRule(); LispMultiUserFunction* multiUserFunc = &i->second; // Get the specific user function with the right arity LispUserFunction* userFunc = multiUserFunc->UserFunc(aArity); if (!userFunc) throw LispErrCreatingRule(); // Declare a new evaluation rule userFunc->DeclarePattern(aPrecedence, aPredicate, aBody); } void LispEnvironment::SetCommand(YacasEvalCaller aEvaluatorFunc, const char* aString, int aNrArgs, int aFlags) { const LispString* name = HashTable().LookUp(aString); YacasEvaluator eval(aEvaluatorFunc, aNrArgs, aFlags); auto i = iCoreCommands.find(name); if (i != iCoreCommands.end()) i->second = eval; else iCoreCommands.insert(std::make_pair(name, eval)); } void LispEnvironment::RemoveCoreCommand(char* aString) { iCoreCommands.erase(HashTable().LookUp(aString)); } LispLocalEvaluator::LispLocalEvaluator(LispEnvironment& aEnvironment, LispEvaluatorBase* aNewEvaluator) : iPreviousEvaluator(aEnvironment.iEvaluator), iEnvironment(aEnvironment) { aEnvironment.iEvaluator = aNewEvaluator; } LispLocalEvaluator::~LispLocalEvaluator() { delete iEnvironment.iEvaluator; iEnvironment.iEvaluator = iPreviousEvaluator; } LispLocalTrace::LispLocalTrace(LispUserFunction* aUserFunc) : iUserFunc(aUserFunc) { if (iUserFunc != nullptr) iUserFunc->Trace(); } LispLocalTrace::~LispLocalTrace() { if (iUserFunc != nullptr) iUserFunc->UnTrace(); } ================================================ FILE: cyacas/libyacas/src/lisperror.cpp ================================================ #include "yacas/lisperror.h" #include "yacas/lispenvironment.h" #include "yacas/standard.h" void HandleError(const LispError& error, LispEnvironment& aEnvironment, std::ostream& aOutput) { if (aEnvironment.iInputStatus.LineNumber() >= 0) { aOutput << aEnvironment.iInputStatus.FileName(); aOutput << "("; aOutput << aEnvironment.iInputStatus.LineNumber(); aOutput << ") : "; } // aEnvironment.iCleanup.Delete(); aOutput << error.what() << '\n'; } ================================================ FILE: cyacas/libyacas/src/lispeval.cpp ================================================ #include "yacas/lispeval.h" #include "yacas/lispuserfunc.h" #include "yacas/standard.h" #include "yacas/errors.h" #include "yacas/infixparser.h" #include "yacas/lispio.h" #include "yacas/platfileio.h" #include #include LispUserFunction* GetUserFunction(LispEnvironment& aEnvironment, LispPtr* subList) { LispObject* head = (*subList); LispUserFunction* userFunc = aEnvironment.UserFunction(*subList); if (userFunc) { return userFunc; } else if (head->String() != nullptr) { LispMultiUserFunction* multiUserFunc = aEnvironment.MultiUserFunction(head->String()); if (multiUserFunc->iFileToOpen != nullptr) { LispDefFile* def = multiUserFunc->iFileToOpen; multiUserFunc->iFileToOpen = nullptr; InternalUse(aEnvironment, def->FileName()); } userFunc = aEnvironment.UserFunction(*subList); } return userFunc; } UserStackInformation& LispEvaluatorBase::StackInformation() { return iBasicInfo; } void LispEvaluatorBase::ResetStack() {} void LispEvaluatorBase::ShowStack(LispEnvironment& aEnvironment, std::ostream& aOutput) { } // Eval: evaluates an expression. The result of this operation must // be a unique (copied) element! Eg. its Nixed might be set... void BasicEvaluator::Eval(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) { assert(aExpression); if (aEnvironment.stop_evaluation) { aEnvironment.stop_evaluation = false; ShowStack(aEnvironment, aEnvironment.CurrentOutput()); throw LispErrUserInterrupt(); } aEnvironment.iEvalDepth++; if (aEnvironment.iEvalDepth >= aEnvironment.iMaxEvalDepth) { ShowStack(aEnvironment, aEnvironment.CurrentOutput()); throw LispErrMaxRecurseDepthReached(); } const LispString* str = aExpression->String(); // Evaluate an atom: find the bound value (treat it as a variable) if (str) { if (str->front() == '\"') { aResult = aExpression->Copy(); goto FINISH; } LispPtr val; aEnvironment.GetVariable(str, val); if (!!val) { aResult = (val->Copy()); goto FINISH; } aResult = (aExpression->Copy()); goto FINISH; } { LispPtr* subList = aExpression->SubList(); if (subList) { LispObject* head = (*subList); if (head) { if (head->String()) { { const auto i = aEnvironment.CoreCommands().find(head->String()); if (i != aEnvironment.CoreCommands().end()) { i->second.Evaluate(aResult, aEnvironment, *subList); goto FINISH; } } { LispUserFunction* userFunc; userFunc = GetUserFunction(aEnvironment, subList); if (userFunc) { userFunc->Evaluate(aResult, aEnvironment, *subList); goto FINISH; } } } else { LispPtr oper((*subList)); LispPtr args2((*subList)->Nixed()); InternalApplyPure(oper, args2, aResult, aEnvironment); goto FINISH; } ReturnUnEvaluated(aResult, *subList, aEnvironment); goto FINISH; } } aResult = (aExpression->Copy()); } FINISH: aEnvironment.iEvalDepth--; } void ShowExpression(LispString& outString, LispEnvironment& aEnvironment, LispPtr& aExpression) { InfixPrinter infixprinter(aEnvironment.PreFix(), aEnvironment.InFix(), aEnvironment.PostFix(), aEnvironment.Bodied()); // Print out the current expression std::ostringstream stream; infixprinter.Print(aExpression, stream, aEnvironment); outString.append(stream.str()); std::regex_replace( outString, std::regex("(^\")|([^\\\\]\")"), std::string("\\\"")); } static void TraceShowExpression(LispEnvironment& aEnvironment, LispPtr& aExpression) { LispString outString; ShowExpression(outString, aEnvironment, aExpression); aEnvironment.CurrentOutput().write(outString.c_str(), outString.size()); } void TraceShowArg(LispEnvironment& aEnvironment, LispPtr& aParam, LispPtr& aValue) { for (int i = 0; i < aEnvironment.iEvalDepth + 2; i++) aEnvironment.CurrentOutput().write(" ", 2); aEnvironment.CurrentOutput() << "TrArg(\""; TraceShowExpression(aEnvironment, aParam); aEnvironment.CurrentOutput() << "\",\""; TraceShowExpression(aEnvironment, aValue); aEnvironment.CurrentOutput() << "\");\n"; } void TraceShowEnter(LispEnvironment& aEnvironment, LispPtr& aExpression) { for (int i = 0; i < aEnvironment.iEvalDepth; i++) aEnvironment.CurrentOutput().write(" ", 2); aEnvironment.CurrentOutput() << "TrEnter(\""; { const char* function = ""; if (aExpression->SubList()) { LispPtr* sub = aExpression->SubList(); if ((*sub)->String()) function = (*sub)->String()->c_str(); } aEnvironment.CurrentOutput() << function; } aEnvironment.CurrentOutput() << "\",\""; TraceShowExpression(aEnvironment, aExpression); aEnvironment.CurrentOutput() << "\",\""; aEnvironment.CurrentOutput() << ""; // file aEnvironment.CurrentOutput() << "\","; aEnvironment.CurrentOutput() << "0"; // line aEnvironment.CurrentOutput() << ");\n"; } void TraceShowLeave(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) { for (int i = 0; i < aEnvironment.iEvalDepth; i++) aEnvironment.CurrentOutput().write(" ", 2); aEnvironment.CurrentOutput().write("TrLeave(\"", 9); TraceShowExpression(aEnvironment, aExpression); aEnvironment.CurrentOutput().write("\",\"", 3); TraceShowExpression(aEnvironment, aResult); aEnvironment.CurrentOutput().write("\");\n", 4); } void TracedStackEvaluator::PushFrame() { UserStackInformation* op = new UserStackInformation; objs.push_back(op); } void TracedStackEvaluator::PopFrame() { assert(!objs.empty()); delete objs.back(); objs.pop_back(); } void TracedStackEvaluator::ResetStack() { while (!objs.empty()) PopFrame(); } UserStackInformation& TracedStackEvaluator::StackInformation() { return *objs.back(); } TracedStackEvaluator::~TracedStackEvaluator() { ResetStack(); } void TracedStackEvaluator::ShowStack(LispEnvironment& aEnvironment, std::ostream& aOutput) { LispLocalEvaluator local(aEnvironment, new BasicEvaluator); const std::size_t upto = objs.size(); for (std::size_t i = 0; i < upto; ++i) { aEnvironment.CurrentOutput() << i << ": "; aEnvironment.CurrentPrinter().Print( objs[i]->iOperator, aEnvironment.CurrentOutput(), aEnvironment); int internal; internal = aEnvironment.CoreCommands().find(objs[i]->iOperator->String()) != aEnvironment.CoreCommands().end(); if (internal) { aEnvironment.CurrentOutput() << " (Internal function) "; } else { if (objs[i]->iRulePrecedence >= 0) { aEnvironment.CurrentOutput() << " (Rule # " << objs[i]->iRulePrecedence; if (objs[i]->iSide) aEnvironment.CurrentOutput() << " in body) "; else aEnvironment.CurrentOutput() << " in pattern) "; } else aEnvironment.CurrentOutput() << " (User function) "; } if (!!objs[i]->iExpression) { aEnvironment.CurrentOutput() << "\n "; if (aEnvironment.iEvalDepth > (aEnvironment.iMaxEvalDepth - 10)) { LispString expr; PrintExpression(expr, objs[i]->iExpression, aEnvironment, 60); aEnvironment.CurrentOutput() << expr; } else { LispPtr* subList = objs[i]->iExpression->SubList(); if (!!subList && !!(*subList)) { LispString expr; LispPtr out(objs[i]->iExpression); PrintExpression(expr, out, aEnvironment, 60); aEnvironment.CurrentOutput() << expr; } } } aEnvironment.CurrentOutput() << '\n'; } } void TracedStackEvaluator::Eval(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) { if (aEnvironment.iEvalDepth >= aEnvironment.iMaxEvalDepth) { ShowStack(aEnvironment, aEnvironment.CurrentOutput()); throw LispErrMaxRecurseDepthReached(); } LispPtr* subList = aExpression->SubList(); const LispString* str = nullptr; if (subList) { LispObject* head = (*subList); if (head) { str = head->String(); if (str) { PushFrame(); UserStackInformation& st = StackInformation(); st.iOperator = LispAtom::New(aEnvironment, *str); st.iExpression = aExpression; } } } BasicEvaluator::Eval(aEnvironment, aResult, aExpression); if (str) { PopFrame(); } } void TracedEvaluator::Eval(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) { if (!aEnvironment.iDebugger) throw LispErrGeneric("Internal error: debugging failing"); if (aEnvironment.iDebugger->Stopped()) throw LispErrGeneric(""); REENTER: errorOutput.clear(); errorOutput.str(""); try { aEnvironment.iDebugger->Enter(aEnvironment, aExpression); } catch (const LispError& error) { HandleError(error, aEnvironment, errorOutput); } if (aEnvironment.iDebugger->Stopped()) throw LispErrGeneric(""); if (!errorOutput.str().empty()) { aEnvironment.CurrentOutput() << errorOutput.str(); aEnvironment.iEvalDepth = 0; goto REENTER; } errorOutput.clear(); errorOutput.str(""); try { BasicEvaluator::Eval(aEnvironment, aResult, aExpression); } catch (const LispError& error) { HandleError(error, aEnvironment, errorOutput); } if (!errorOutput.str().empty()) { aEnvironment.CurrentOutput() << errorOutput.str(); aEnvironment.iEvalDepth = 0; aEnvironment.iDebugger->Error(aEnvironment); goto REENTER; } if (aEnvironment.iDebugger->Stopped()) throw LispErrGeneric(""); aEnvironment.iDebugger->Leave(aEnvironment, aResult, aExpression); if (aEnvironment.iDebugger->Stopped()) throw LispErrGeneric(""); } void DefaultDebugger::Start() {} void DefaultDebugger::Finish() {} void DefaultDebugger::Enter(LispEnvironment& aEnvironment, LispPtr& aExpression) { LispLocalEvaluator local(aEnvironment, new BasicEvaluator); iTopExpr = (aExpression->Copy()); LispPtr result; defaultEval.Eval(aEnvironment, result, iEnter); } void DefaultDebugger::Leave(LispEnvironment& aEnvironment, LispPtr& aResult, LispPtr& aExpression) { LispLocalEvaluator local(aEnvironment, new BasicEvaluator); LispPtr result; iTopExpr = (aExpression->Copy()); iTopResult = (aResult); defaultEval.Eval(aEnvironment, result, iLeave); } bool DefaultDebugger::Stopped() { return iStopped; } void DefaultDebugger::Error(LispEnvironment& aEnvironment) { LispLocalEvaluator local(aEnvironment, new BasicEvaluator); LispPtr result; defaultEval.Eval(aEnvironment, result, iError); } ================================================ FILE: cyacas/libyacas/src/lispevalhash.cpp ================================================ #include "yacas/lispevalhash.h" #include "yacas/errors.h" #include "yacas/lispatom.h" #include "yacas/lispenvironment.h" #include "yacas/lispeval.h" void YacasEvaluator::Evaluate(LispPtr& aResult, LispEnvironment& aEnvironment, LispPtr& aArguments) const { if (!(iFlags & Variable)) { CheckNrArgs(iNrArgs + 1, aArguments, aEnvironment); } int stacktop = aEnvironment.iStack.size(); // Push a place holder for the result: push full expression so it is // available for error reporting aEnvironment.iStack.push_back(aArguments); LispIterator iter(aArguments); ++iter; int i; int nr = iNrArgs; if (iFlags & Variable) nr--; // Walk over all arguments, evaluating them as necessary if (iFlags & Macro) { for (i = 0; i < nr; i++) { if (!iter.getObj()) throw LispErrWrongNumberOfArgs(); aEnvironment.iStack.push_back(LispPtr(iter.getObj()->Copy())); ++iter; } if (iFlags & Variable) { LispPtr head(aEnvironment.iList->Copy()); head->Nixed() = (iter.getObj()); aEnvironment.iStack.push_back(LispPtr(LispSubList::New(head))); } } else { LispPtr arg; for (i = 0; i < nr; i++) { if (!iter.getObj()) throw LispErrWrongNumberOfArgs(); aEnvironment.iEvaluator->Eval(aEnvironment, arg, *iter); aEnvironment.iStack.push_back(arg); ++iter; } if (iFlags & Variable) { LispPtr head(aEnvironment.iList->Copy()); head->Nixed() = (iter.getObj()); LispPtr list(LispSubList::New(head)); aEnvironment.iEvaluator->Eval(aEnvironment, arg, list); aEnvironment.iStack.push_back(arg); } } iCaller(aEnvironment, stacktop); aResult = (aEnvironment.iStack[stacktop]); aEnvironment.iStack.resize(stacktop); } ================================================ FILE: cyacas/libyacas/src/lisphash.cpp ================================================ #include "yacas/lisphash.h" const LispString* LispHashTable::LookUp(const std::string& s) { std::unordered_map::const_iterator i = _rep.find(s); if (i != _rep.end()) return i->second; LispString* ls = new LispString(s); return _rep.insert(std::make_pair(s, ls)).first->second; } void LispHashTable::GarbageCollect() { for (auto i = _rep.begin(); i != _rep.end(); ++i) while (i != _rep.end() && i->second->use_count() == 1) i = _rep.erase(i); } ================================================ FILE: cyacas/libyacas/src/lispio.cpp ================================================ #include "yacas/lispio.h" void InputStatus::SetTo(const std::string& aFileName) { iFileName = aFileName; iLineNumber = 1; } void InputStatus::RestoreFrom(InputStatus& aPreviousStatus) { iLineNumber = aPreviousStatus.iLineNumber; iFileName = aPreviousStatus.iFileName; } ================================================ FILE: cyacas/libyacas/src/lispobject.cpp ================================================ #include "yacas/lispobject.h" int LispObject::Equal(LispObject& aOther) { // next line handles the fact that either one is a string if (String() != aOther.String()) return 0; // return false // So, no strings. LispPtr* iter1 = SubList(); LispPtr* iter2 = aOther.SubList(); assert(!!iter1 && !!iter2); // check all elements in sublist while (!!(*iter1) && !!(*iter2)) { if (!(*iter1)->Equal(*(*iter2))) return 0; iter1 = &(*iter1)->Nixed(); iter2 = &(*iter2)->Nixed(); } // One list longer than the other? if (!(*iter1) && !(*iter2)) return 1; return 0; } ================================================ FILE: cyacas/libyacas/src/lispparser.cpp ================================================ #include "yacas/lispparser.h" #include "yacas/lispatom.h" #include "yacas/lispenvironment.h" #include "yacas/lisperror.h" LispParser::LispParser(LispTokenizer& aTokenizer, LispInput& aInput, LispEnvironment& aEnvironment) : iTokenizer(aTokenizer), iInput(aInput), iEnvironment(aEnvironment), iListed(false) { } void LispParser::Parse(LispPtr& aResult) { aResult = nullptr; // Get token. const LispString* token = iEnvironment.HashTable().LookUp(iTokenizer.NextToken(iInput)); if (token->empty()) { aResult = iEnvironment.iEndOfFile->Copy(); return; } ParseAtom(aResult, token); } void LispParser::ParseAtom(LispPtr& aResult, const LispString* aToken) { // if token is empty string, return null pointer (no expression) if (aToken->empty()) return; // else if token is "(" read in a whole array of objects until ")", // and make a sublist if (aToken == iEnvironment.iBracketOpen->String()) { LispPtr subList; ParseList(subList); aResult = LispSubList::New(subList); return; } // else make a simple atom, and return it. aResult = LispAtom::New(iEnvironment, *aToken); } void LispParser::ParseList(LispPtr& aResult) { LispPtr* iter = &aResult; if (iListed) { aResult = iEnvironment.iList->Copy(); iter = &(aResult->Nixed()); } for (;;) { // Get token. const LispString* token = iEnvironment.HashTable().LookUp(iTokenizer.NextToken(iInput)); // if token is empty string, error! if (token->empty()) throw InvalidToken(); // if token is ")" return result. if (token == iEnvironment.iBracketClose->String()) return; // else parse simple atom with Parse, and append it to the // results list. ParseAtom(*iter, token); iter = &((*iter)->Nixed()); } } void LispPrinter::Print(const LispPtr& aExpression, std::ostream& aOutput, LispEnvironment& aEnvironment) { PrintExpression(aExpression, aOutput, aEnvironment, 0); } void LispPrinter::Indent(std::ostream& aOutput, int aDepth) { aOutput.put('\n'); int i; for (i = aDepth; i > 0; i--) { aOutput.write(" ", 2); } } void LispPrinter::PrintExpression(const LispPtr& aExpression, std::ostream& aOutput, LispEnvironment& aEnvironment, int aDepth) { const LispPtr* iter = &aExpression; int item = 0; while (!!(*iter)) { // if String not null pointer: print string const LispString* string = (*iter)->String(); if (string) { aOutput << *string << ' '; } // else print "(", print sublist, and print ")" else if ((*iter)->SubList()) { if (item != 0) { Indent(aOutput, aDepth + 1); } aOutput.put('('); PrintExpression( *((*iter)->SubList()), aOutput, aEnvironment, aDepth + 1); aOutput.put(')'); item = 0; } else { aOutput << "[GenericObject]"; } iter = &((*iter)->Nixed()); item++; } // print next element } // does nothing in the LispPrinter but is used in derived classes void LispPrinter::RememberLastChar(char aChar) {} ================================================ FILE: cyacas/libyacas/src/lispuserfunc.cpp ================================================ #include "yacas/lispuserfunc.h" #include "yacas/standard.h" LispUserFunction* LispMultiUserFunction::UserFunc(int aArity) { // Find function body with the right arity for (LispArityUserFunction* p: iFunctions) { assert(p); if (p->IsArity(aArity)) return p; } // if function not found, just unaccept! // User-defined function not found! Returning nullptr return nullptr; } void LispMultiUserFunction::DeleteBase(int aArity) { // Find function body with the right arity const std::size_t nrc = iFunctions.size(); for (std::size_t i = 0; i < nrc; ++i) { assert(iFunctions[i]); if (iFunctions[i]->IsArity(aArity)) { delete iFunctions[i]; iFunctions.erase(iFunctions.begin() + i); return; } } } LispMultiUserFunction::~LispMultiUserFunction() { for (LispArityUserFunction* p : iFunctions) delete p; } void LispMultiUserFunction::HoldArgument(const LispString* aVariable) { const std::size_t n = iFunctions.size(); for (std::size_t i = 0; i < n; ++i) { assert(iFunctions[i]); iFunctions[i]->HoldArgument(aVariable); } } void LispMultiUserFunction::DefineRuleBase(LispArityUserFunction* aNewFunction) { // Find function body with the right arity const std::size_t nrc = iFunctions.size(); for (std::size_t i = 0; i < nrc; ++i) { assert(iFunctions[i]); assert(aNewFunction); if (iFunctions[i]->IsArity(aNewFunction->Arity()) || aNewFunction->IsArity(iFunctions[i]->Arity())) throw LispErrArityAlreadyDefined(); } iFunctions.push_back(aNewFunction); } ================================================ FILE: cyacas/libyacas/src/mathcommands.cpp ================================================ #include "yacas/arggetter.h" #include "yacas/arrayclass.h" #include "yacas/associationclass.h" #include "yacas/errors.h" #include "yacas/infixparser.h" #include "yacas/lispatom.h" #include "yacas/lispenvironment.h" #include "yacas/lisperror.h" #include "yacas/lispeval.h" #include "yacas/lispparser.h" #include "yacas/lispuserfunc.h" #include "yacas/mathuserfunc.h" #include "yacas/numbers.h" #include "yacas/patternclass.h" #include "yacas/platfileio.h" #include "yacas/platmath.h" #include "yacas/standard.h" #include "yacas/string_utils.h" #include "yacas/stringio.h" #include "yacas/substitute.h" #include #include #include #include #include #ifdef _WIN32 # include #else # include #endif #define InternalEval aEnvironment.iEvaluator->Eval #define RESULT aEnvironment.iStack[aStackTop] #define ARGUMENT(i) aEnvironment.iStack[aStackTop + i] void LispLexCompare2(LispEnvironment& aEnvironment, int aStackTop, bool (*lexfunc)(const char* f1, const char* f2, LispHashTable& aHashTable, int aPrecision), bool (*numfunc)(BigNumber& n1, BigNumber& n2)); void LispQuote(LispEnvironment& aEnvironment, int aStackTop) { RESULT = (ARGUMENT(1)->Copy()); } void LispEval(LispEnvironment& aEnvironment, int aStackTop) { InternalEval(aEnvironment, RESULT, ARGUMENT(1)); } /// Execute the Yacas commands \c Set and \c MacroSet. /// The argument \a aMacroMode determines whether the first argument /// should be evaluated. The real work is done by /// LispEnvironment::SetVariable() . /// \sa LispSetVar(), LispMacroSetVar() static void InternalSetVar(LispEnvironment& aEnvironment, int aStackTop, bool aMacroMode, bool aGlobalLazyVariable) { const LispString* varstring = nullptr; if (aMacroMode) { LispPtr result; InternalEval(aEnvironment, result, ARGUMENT(1)); varstring = result->String(); } else { varstring = ARGUMENT(1)->String(); } CheckArg(varstring, 1, aEnvironment, aStackTop); CheckArg(!IsNumber(*varstring, true), 1, aEnvironment, aStackTop); LispPtr result; InternalEval(aEnvironment, result, ARGUMENT(2)); aEnvironment.SetVariable(varstring, result, aGlobalLazyVariable); InternalTrue(aEnvironment, RESULT); } /// Corresponds to the Yacas function \c Set. /// This function simply calls InternalSetVar() . void LispSetVar(LispEnvironment& aEnvironment, int aStackTop) { InternalSetVar(aEnvironment, aStackTop, false, false); } /// Corresponds to the Yacas function \c MacroSet. /// This function simply calls InternalSetVar() . void LispMacroSetVar(LispEnvironment& aEnvironment, int aStackTop) { InternalSetVar(aEnvironment, aStackTop, true, false); } void LispSetGlobalLazyVariable(LispEnvironment& aEnvironment, int aStackTop) { InternalSetVar(aEnvironment, aStackTop, false, true); } void LispClearVar(LispEnvironment& aEnvironment, int aStackTop) { LispPtr* subList = ARGUMENT(1)->SubList(); if (subList) { LispIterator iter(*subList); for (int nr = 1; (++iter).getObj(); nr++) { const LispString* str = iter.getObj()->String(); CheckArg(str, nr, aEnvironment, aStackTop); aEnvironment.UnsetVariable(str); } } InternalTrue(aEnvironment, RESULT); } void LispVars(LispEnvironment& aEnvironment, int aStackTop) { LispPtr vars; aEnvironment.GlobalVariables(vars); RESULT = vars; } /* StrCompare returns f1-f2: if f1 < f2 it returns -1, if f1=f2 it returns 0, and it returns 1 if f1>f2 */ // the aPrecision argument is ignored here static bool LexLessThan(const char* f1, const char* f2, LispHashTable& aHashTable, int aPrecision) { return (std::strcmp(f1, f2) < 0); } // the aPrecision argument is ignored here static bool LexGreaterThan(const char* f1, const char* f2, LispHashTable& aHashTable, int aPrecision) { return (std::strcmp(f1, f2) > 0); } static bool BigLessThan(BigNumber& n1, BigNumber& n2) { return n1.LessThan(n2) && !n1.Equals(n2); } static bool BigGreaterThan(BigNumber& n1, BigNumber& n2) { return !(n1.LessThan(n2) || n1.Equals(n2)); } void LispStrictTotalOrder(LispEnvironment& aEnvironment, int aStackTop) { LispPtr e1(ARGUMENT(1)); LispPtr e2(ARGUMENT(2)); InternalBoolean( aEnvironment, RESULT, InternalStrictTotalOrder(aEnvironment, e1, e2)); } void LispLessThan(LispEnvironment& aEnvironment, int aStackTop) { LispLexCompare2(aEnvironment, aStackTop, LexLessThan, BigLessThan); } void LispGreaterThan(LispEnvironment& aEnvironment, int aStackTop) { LispLexCompare2(aEnvironment, aStackTop, LexGreaterThan, BigGreaterThan); } void LispLexCompare2(LispEnvironment& aEnvironment, int aStackTop, bool (*lexfunc)(const char* f1, const char* f2, LispHashTable& aHashTable, int aPrecision), bool (*numfunc)(BigNumber& n1, BigNumber& n2)) { LispPtr result1(ARGUMENT(1)); LispPtr result2(ARGUMENT(2)); bool cmp; BigNumber* n1 = result1->Number(aEnvironment.Precision()); BigNumber* n2 = result2->Number(aEnvironment.Precision()); if (n1 && n2) { cmp = numfunc(*n1, *n2); } else { const LispString* str1 = result1->String(); const LispString* str2 = result2->String(); CheckArg(str1, 1, aEnvironment, aStackTop); CheckArg(str2, 2, aEnvironment, aStackTop); // the precision argument is ignored in "lex" functions cmp = lexfunc(str1->c_str(), str2->c_str(), aEnvironment.HashTable(), aEnvironment.Precision()); } InternalBoolean(aEnvironment, RESULT, cmp); } void LispFullForm(LispEnvironment& aEnvironment, int aStackTop) { RESULT = (ARGUMENT(1)); LispPrinter printer; printer.Print(RESULT, aEnvironment.CurrentOutput(), aEnvironment); aEnvironment.CurrentOutput().put('\n'); } void LispHead(LispEnvironment& aEnvironment, int aStackTop) { InternalNth(RESULT, ARGUMENT(1), 1); } void LispNth(LispEnvironment& aEnvironment, int aStackTop) { const LispString* str = ARGUMENT(2)->String(); CheckArg(str, 2, aEnvironment, aStackTop); CheckArg(IsNumber(str->c_str(), false), 2, aEnvironment, aStackTop); int index = InternalAsciiToInt(*str); InternalNth(RESULT, ARGUMENT(1), index); } void LispTail(LispEnvironment& aEnvironment, int aStackTop) { LispPtr first; InternalTail(first, ARGUMENT(1)); InternalTail(RESULT, first); LispPtr head(aEnvironment.iList->Copy()); head->Nixed() = ((*RESULT->SubList())); (*RESULT->SubList()) = (head); } void LispUnList(LispEnvironment& aEnvironment, int aStackTop) { CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); CheckArg(ARGUMENT(1)->SubList(), 1, aEnvironment, aStackTop); LispObject* subList = (*ARGUMENT(1)->SubList()); CheckArg(subList, 1, aEnvironment, aStackTop); CheckArg(subList->String() == aEnvironment.iList->String(), 1, aEnvironment, aStackTop); InternalTail(RESULT, ARGUMENT(1)); } void LispListify(LispEnvironment& aEnvironment, int aStackTop) { CheckArg(ARGUMENT(1)->SubList(), 1, aEnvironment, aStackTop); LispPtr head(aEnvironment.iList->Copy()); head->Nixed() = ((*ARGUMENT(1)->SubList())); RESULT = (LispSubList::New(head)); } void LispDestructiveReverse(LispEnvironment& aEnvironment, int aStackTop) { CheckArgIsList(1, aEnvironment, aStackTop); LispPtr reversed(aEnvironment.iList->Copy()); InternalReverseList(reversed->Nixed(), (*ARGUMENT(1)->SubList())->Nixed()); RESULT = (LispSubList::New(reversed)); } void LispLength(LispEnvironment& aEnvironment, int aStackTop) { std::size_t size = 0; if (LispPtr* subList = ARGUMENT(1)->SubList()) { size = InternalListLength((*subList)->Nixed()); } else if (InternalIsString(ARGUMENT(1)->String())) { size = ARGUMENT(1)->String()->size() - 2; } else if (ArrayClass* arr = dynamic_cast(ARGUMENT(1)->Generic())) { size = arr->Size(); } else if (AssociationClass* assoc = dynamic_cast(ARGUMENT(1)->Generic())) { size = assoc->Size(); } else CheckArg(false, 1, aEnvironment, aStackTop); RESULT = LispAtom::New(aEnvironment, std::to_string(size)); } void LispList(LispEnvironment& aEnvironment, int aStackTop) { LispPtr all(aEnvironment.iList->Copy()); LispIterator tail(all); ++tail; LispIterator iter(*ARGUMENT(1)->SubList()); while ((++iter).getObj()) { LispPtr evaluated; InternalEval(aEnvironment, evaluated, *iter); // Ideally this would work, but it does not yet: (*tail++) = (evaluated) (*tail) = (evaluated); ++tail; } RESULT = (LispSubList::New(all)); } void LispConcatenate(LispEnvironment& aEnvironment, int aStackTop) { LispPtr all(aEnvironment.iList->Copy()); LispIterator tail(all); ++tail; LispIterator iter(*ARGUMENT(1)->SubList()); for (int arg = 1; (++iter).getObj(); arg++) { CheckArgIsList(*iter, arg, aEnvironment, aStackTop); InternalFlatCopy( *tail, (*(*iter)->SubList())->Nixed()); // TODO: woof -- prefer below // InternalFlatCopy(*tail,iter.getObj()->Nixed()); while (tail.getObj()) ++tail; } RESULT = (LispSubList::New(all)); } void LispConcatenateStrings(LispEnvironment& aEnvironment, int aStackTop) { std::string s; s.push_back('\"'); int arg = 1; for (LispIterator iter(*ARGUMENT(1)->SubList()); (++iter).getObj();) { CheckArgIsString(*iter, arg++, aEnvironment, aStackTop); const std::string& p = *iter.getObj()->String(); s.append(p.substr(1, p.size() - 2)); } s.push_back('\"'); RESULT = LispAtom::New(aEnvironment, s); } static void InternalDelete(LispEnvironment& aEnvironment, int aStackTop, int aDestructive) { LispPtr evaluated(ARGUMENT(1)); CheckArgIsList(1, aEnvironment, aStackTop); LispPtr copied; if (aDestructive) { copied = ((*evaluated->SubList())); } else { InternalFlatCopy(copied, *evaluated->SubList()); } LispPtr index(ARGUMENT(2)); CheckArg(index, 2, aEnvironment, aStackTop); CheckArg(index->String(), 2, aEnvironment, aStackTop); int ind = InternalAsciiToInt(*index->String()); CheckArg(ind > 0, 2, aEnvironment, aStackTop); LispIterator iter(copied); while (--ind >= 0) ++iter; if (!iter.getObj()) { ShowStack(aEnvironment); throw LispErrListNotLongEnough(); } LispIterator temp = iter++; (*temp) = (*iter); RESULT = (LispSubList::New(copied)); } void LispDelete(LispEnvironment& aEnvironment, int aStackTop) { InternalDelete(aEnvironment, aStackTop, false); } void LispDestructiveDelete(LispEnvironment& aEnvironment, int aStackTop) { InternalDelete(aEnvironment, aStackTop, true); } void LispFlatCopy(LispEnvironment& aEnvironment, int aStackTop) { LispPtr copied; if (ARGUMENT(1)->SubList() == nullptr) CheckArgIsList(1, aEnvironment, aStackTop); InternalFlatCopy(copied, *ARGUMENT(1)->SubList()); RESULT = (LispSubList::New(copied)); } static void InternalInsert(LispEnvironment& aEnvironment, int aStackTop, int aDestructive) { CheckArgIsList(1, aEnvironment, aStackTop); LispPtr evaluated(ARGUMENT(1)); LispPtr copied; if (aDestructive) { copied = ((*evaluated->SubList())); } else { InternalFlatCopy(copied, *evaluated->SubList()); } LispPtr index(ARGUMENT(2)); CheckArg(index, 2, aEnvironment, aStackTop); CheckArg(index->String(), 2, aEnvironment, aStackTop); int ind = InternalAsciiToInt(*index->String()); CheckArg(ind > 0, 2, aEnvironment, aStackTop); LispIterator iter(copied); while (--ind >= 0) ++iter; LispPtr toInsert(ARGUMENT(3)); toInsert->Nixed() = (iter.getObj()); (*iter) = (toInsert); RESULT = (LispSubList::New(copied)); } void LispInsert(LispEnvironment& aEnvironment, int aStackTop) { InternalInsert(aEnvironment, aStackTop, false); } void LispDestructiveInsert(LispEnvironment& aEnvironment, int aStackTop) { InternalInsert(aEnvironment, aStackTop, true); } static void InternalReplace(LispEnvironment& aEnvironment, int aStackTop, int aDestructive) { LispPtr evaluated(ARGUMENT(1)); // CHK_ISLIST_CORE(evaluated,1); // Ok, so lets not check if it is a list, but it needs to be at least a // 'function' CheckArg(evaluated->SubList(), 1, aEnvironment, aStackTop); LispPtr index(ARGUMENT(2)); CheckArg(index, 2, aEnvironment, aStackTop); CheckArg(index->String(), 2, aEnvironment, aStackTop); int ind = InternalAsciiToInt(*index->String()); LispPtr copied; if (aDestructive) { copied = ((*evaluated->SubList())); } else { InternalFlatCopy(copied, *evaluated->SubList()); } CheckArg(ind > 0, 2, aEnvironment, aStackTop); LispIterator iter(copied); while (--ind >= 0) ++iter; LispPtr toInsert(ARGUMENT(3)); CheckArg(iter.getObj(), 2, aEnvironment, aStackTop); LispIterator temp = iter++; toInsert->Nixed() = (*iter); (*temp) = (toInsert); RESULT = (LispSubList::New(copied)); } void LispReplace(LispEnvironment& aEnvironment, int aStackTop) { InternalReplace(aEnvironment, aStackTop, false); } void LispDestructiveReplace(LispEnvironment& aEnvironment, int aStackTop) { InternalReplace(aEnvironment, aStackTop, true); } void LispNot(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); if (IsTrue(aEnvironment, evaluated) || IsFalse(aEnvironment, evaluated)) { InternalNot(RESULT, aEnvironment, evaluated); } else { LispPtr ptr(ARGUMENT(0)->Copy()); ptr->Nixed() = (evaluated); RESULT = (LispSubList::New(ptr)); } } void LispLazyAnd(LispEnvironment& aEnvironment, int aStackTop) { LispPtr nogos; int nrnogos = 0; LispPtr evaluated; LispIterator iter(*ARGUMENT(1)->SubList()); while ((++iter).getObj()) { InternalEval(aEnvironment, evaluated, *iter); if (IsFalse(aEnvironment, evaluated)) { InternalFalse(aEnvironment, RESULT); return; } else if (!IsTrue(aEnvironment, evaluated)) { nrnogos++; LispPtr ptr(evaluated->Copy()); ptr->Nixed() = (nogos); nogos = (ptr); } } if (!!nogos) { if (nrnogos == 1) { RESULT = (nogos); } else { LispPtr ptr; InternalReverseList(ptr, nogos); nogos = (ptr); ptr = (ARGUMENT(0)->Copy()); ptr->Nixed() = (nogos); nogos = (ptr); RESULT = (LispSubList::New(nogos)); // aEnvironment.CurrentPrinter().Print(RESULT, // *aEnvironment.CurrentOutput()); } } else { InternalTrue(aEnvironment, RESULT); } } void LispLazyOr(LispEnvironment& aEnvironment, int aStackTop) { LispPtr nogos; int nrnogos = 0; LispPtr evaluated; LispIterator iter(*ARGUMENT(1)->SubList()); while ((++iter).getObj()) { InternalEval(aEnvironment, evaluated, *iter); if (IsTrue(aEnvironment, evaluated)) { InternalTrue(aEnvironment, RESULT); return; } else if (!IsFalse(aEnvironment, evaluated)) { nrnogos++; LispPtr ptr(evaluated->Copy()); ptr->Nixed() = (nogos); nogos = (ptr); } } if (!!nogos) { if (nrnogos == 1) { RESULT = (nogos); } else { LispPtr ptr; InternalReverseList(ptr, nogos); nogos = (ptr); ptr = (ARGUMENT(0)->Copy()); ptr->Nixed() = (nogos); nogos = (ptr); RESULT = (LispSubList::New(nogos)); } // aEnvironment.CurrentPrinter().Print(RESULT, // *aEnvironment.CurrentOutput()); } else { InternalFalse(aEnvironment, RESULT); } } void LispEquals(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated1(ARGUMENT(1)); LispPtr evaluated2(ARGUMENT(2)); InternalBoolean(aEnvironment, RESULT, InternalEquals(aEnvironment, evaluated1, evaluated2)); } void LispWrite(LispEnvironment& aEnvironment, int aStackTop) { LispPtr* subList = ARGUMENT(1)->SubList(); if (subList) { LispIterator iter(*subList); while ((++iter).getObj()) { aEnvironment.CurrentPrinter().Print( *iter, aEnvironment.CurrentOutput(), aEnvironment); } } InternalTrue(aEnvironment, RESULT); } void LispWriteString(LispEnvironment& aEnvironment, int aStackTop) { CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* str = ARGUMENT(1)->String(); CheckArg(str, 1, aEnvironment, aStackTop); CheckArg((*str)[0] == '\"', 1, aEnvironment, aStackTop); CheckArg((*str)[str->size() - 1] == '\"', 1, aEnvironment, aStackTop); const std::size_t nr = str->size() - 1; //((*str)[i] != '\"') for (std::size_t i = 1; i < nr; ++i) aEnvironment.CurrentOutput().put((*str)[i]); // pass last printed character to the current printer aEnvironment.CurrentPrinter().RememberLastChar( (*str)[nr - 1]); // hacky hacky InternalTrue(aEnvironment, RESULT); } void LispProgBody(LispEnvironment& aEnvironment, int aStackTop) { // Allow accessing previous locals. LispLocalFrame frame(aEnvironment, false); InternalTrue(aEnvironment, RESULT); // Evaluate args one by one. LispIterator iter(*ARGUMENT(1)->SubList()); while ((++iter).getObj()) { InternalEval(aEnvironment, RESULT, *iter); } } void LispNewLocal(LispEnvironment& aEnvironment, int aStackTop) { LispPtr* subList = ARGUMENT(1)->SubList(); if (subList) { LispIterator iter(*subList); for (int nr = 1; (++iter).getObj(); nr++) { const LispString* variable = iter.getObj()->String(); CheckArg(variable, nr, aEnvironment, aStackTop); // printf("Variable %s\n",variable->String()); aEnvironment.NewLocal(variable, nullptr); } } InternalTrue(aEnvironment, RESULT); } void LispWhile(LispEnvironment& aEnvironment, int aStackTop) { LispPtr& arg1 = ARGUMENT(1); LispPtr& arg2 = ARGUMENT(2); LispPtr predicate; InternalEval(aEnvironment, predicate, arg1); while (IsTrue(aEnvironment, predicate)) { LispPtr evaluated; InternalEval(aEnvironment, evaluated, arg2); InternalEval(aEnvironment, predicate, arg1); } CheckArg(IsFalse(aEnvironment, predicate), 1, aEnvironment, aStackTop); InternalTrue(aEnvironment, RESULT); } static void MultiFix(LispEnvironment& aEnvironment, int aStackTop, LispOperators& aOps) { // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); LispPtr precedence; InternalEval(aEnvironment, precedence, ARGUMENT(2)); CheckArg(precedence->String(), 2, aEnvironment, aStackTop); int prec = InternalAsciiToInt(*precedence->String()); CheckArg(prec <= KMaxPrecedence, 2, aEnvironment, aStackTop); aOps[SymbolName(aEnvironment, *orig)] = LispInFixOperator(prec); InternalTrue(aEnvironment, RESULT); } void LispInFix(LispEnvironment& aEnvironment, int aStackTop) { MultiFix(aEnvironment, aStackTop, aEnvironment.InFix()); } static void SingleFix(int aPrecedence, LispEnvironment& aEnvironment, int aStackTop, LispOperators& aOps) { // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); aOps[SymbolName(aEnvironment, *orig)] = LispInFixOperator(aPrecedence); InternalTrue(aEnvironment, RESULT); } void LispPreFix(LispEnvironment& aEnvironment, int aStackTop) { /* int nrArguments = InternalListLength(ARGUMENT(0)); if (nrArguments == 2) { SingleFix(0, aEnvironment, aStackTop, aEnvironment.PreFix()); } else */ { MultiFix(aEnvironment, aStackTop, aEnvironment.PreFix()); } } void LispPostFix(LispEnvironment& aEnvironment, int aStackTop) { const std::size_t nrArguments = InternalListLength(ARGUMENT(0)); if (nrArguments == 2) SingleFix(0, aEnvironment, aStackTop, aEnvironment.PostFix()); else MultiFix(aEnvironment, aStackTop, aEnvironment.PostFix()); } void LispBodied(LispEnvironment& aEnvironment, int aStackTop) { MultiFix(aEnvironment, aStackTop, aEnvironment.Bodied()); } void LispAtomize(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); // Get operator CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); RESULT = LispAtom::New(aEnvironment, orig->substr(1, orig->length() - 2)); } void LispStringify(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); // Get operator CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); RESULT = LispAtom::New(aEnvironment, stringify(*orig)); } void LispLoad(LispEnvironment& aEnvironment, int aStackTop) { CheckSecure(aEnvironment, aStackTop); LispPtr evaluated(ARGUMENT(1)); // Get file name CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); InternalLoad(aEnvironment, *orig); InternalTrue(aEnvironment, RESULT); } void LispTmpFile(LispEnvironment& aEnvironment, int aStackTop) { CheckSecure(aEnvironment, aStackTop); #ifndef _WIN32 char fn[] = "/tmp/yacas-XXXXXX"; int fd = mkstemp(fn); // FIXME: not very clear if (fd < 0) { ShowStack(aEnvironment); throw LispErrFileNotFound(); } close(fd); RESULT = LispAtom::New(aEnvironment, stringify(fn)); #else char tmp_path[MAX_PATH]; char tmp_fn[MAX_PATH]; GetTempPath(MAX_PATH, tmp_path); GetTempFileName(tmp_path, "yacas", 0, tmp_fn); RESULT = LispAtom::New(aEnvironment, stringify(tmp_fn)); #endif } void LispProtect(LispEnvironment& env, int top) { LispPtr p(env.iStack[top + 1]); CheckArg(p, 1, env, top); const LispString* s = p->String(); CheckArg(s, 1, env, top); env.Protect(s); InternalTrue(env, env.iStack[top]); } void LispUnProtect(LispEnvironment& env, int top) { LispPtr p(env.iStack[top + 1]); CheckArg(p, 1, env, top); const LispString* s = p->String(); CheckArg(s, 1, env, top); env.UnProtect(s); InternalTrue(env, env.iStack[top]); } void LispIsProtected(LispEnvironment& env, int top) { LispPtr p(env.iStack[top + 1]); CheckArg(p, 1, env, top); const LispString* s = p->String(); CheckArg(s, 1, env, top); env.iStack[top] = env.Protected(s) ? env.iTrue->Copy() : env.iFalse->Copy(); } /// Implements the Yacas functions \c RuleBase and \c MacroRuleBase . /// The real work is done by LispEnvironment::DeclareRuleBase(). static void InternalRuleBase(LispEnvironment& aEnvironment, int aStackTop, int aListed) { // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); LispPtr args(ARGUMENT(2)); // The arguments CheckArgIsList(2, aEnvironment, aStackTop); // Finally define the rule base aEnvironment.DeclareRuleBase( SymbolName(aEnvironment, *orig), (*args->SubList())->Nixed(), aListed); // Return true InternalTrue(aEnvironment, RESULT); } /// Corresponds to the Yacas function \c RuleBase . /// This function simply calls InternalRuleBase(). void LispRuleBase(LispEnvironment& aEnvironment, int aStackTop) { InternalRuleBase(aEnvironment, aStackTop, false); } void LispMacroRuleBase(LispEnvironment& aEnvironment, int aStackTop) { InternalRuleBase(aEnvironment, aStackTop, false); } void InternalDefMacroRuleBase(LispEnvironment& aEnvironment, int aStackTop, int aListed) { // Get operator // LispPtr body; CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); // The arguments LispPtr args(ARGUMENT(2)); CheckArgIsList(2, aEnvironment, aStackTop); // Finally define the rule base aEnvironment.DeclareMacroRuleBase( SymbolName(aEnvironment, *orig), (*args->SubList())->Nixed(), aListed); // Return true InternalTrue(aEnvironment, RESULT); } void LispDefMacroRuleBaseListed(LispEnvironment& aEnvironment, int aStackTop) { InternalDefMacroRuleBase(aEnvironment, aStackTop, true); } void LispDefMacroRuleBase(LispEnvironment& aEnvironment, int aStackTop) { InternalDefMacroRuleBase(aEnvironment, aStackTop, false); } void LispRuleBaseListed(LispEnvironment& aEnvironment, int aStackTop) { InternalRuleBase(aEnvironment, aStackTop, true); } void LispMacroRuleBaseListed(LispEnvironment& aEnvironment, int aStackTop) { InternalRuleBase(aEnvironment, aStackTop, true); } void LispHoldArg(LispEnvironment& aEnvironment, int aStackTop) { // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); // The arguments const LispString* tohold = ARGUMENT(2)->String(); CheckArg(tohold, 2, aEnvironment, aStackTop); aEnvironment.HoldArgument(SymbolName(aEnvironment, *orig), tohold); // Return true InternalTrue(aEnvironment, RESULT); } static void InternalNewRule(LispEnvironment& aEnvironment, int aStackTop) { int arity; int precedence; LispPtr ar; LispPtr pr; LispPtr predicate; LispPtr body; // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); ar = (ARGUMENT(2)); pr = (ARGUMENT(3)); predicate = (ARGUMENT(4)); body = (ARGUMENT(5)); // The arity CheckArg(ar, 2, aEnvironment, aStackTop); CheckArg(ar->String(), 2, aEnvironment, aStackTop); arity = InternalAsciiToInt(*ar->String()); // The precedence CheckArg(pr, 3, aEnvironment, aStackTop); CheckArg(pr->String(), 3, aEnvironment, aStackTop); precedence = InternalAsciiToInt(*pr->String()); // Finally define the rule base aEnvironment.DefineRule( SymbolName(aEnvironment, *orig), arity, precedence, predicate, body); // Return true InternalTrue(aEnvironment, RESULT); } void LispNewRule(LispEnvironment& aEnvironment, int aStackTop) { InternalNewRule(aEnvironment, aStackTop); } void LispMacroNewRule(LispEnvironment& aEnvironment, int aStackTop) { InternalNewRule(aEnvironment, aStackTop); } void LispUnFence(LispEnvironment& aEnvironment, int aStackTop) { // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); // The arity CheckArg(ARGUMENT(2), 2, aEnvironment, aStackTop); CheckArg(ARGUMENT(2)->String(), 2, aEnvironment, aStackTop); int arity = InternalAsciiToInt(*ARGUMENT(2)->String()); aEnvironment.UnFenceRule(SymbolName(aEnvironment, *orig), arity); // Return true InternalTrue(aEnvironment, RESULT); } void LispIsFunction(LispEnvironment& aEnvironment, int aStackTop) { LispPtr result(ARGUMENT(1)); InternalBoolean(aEnvironment, RESULT, result->SubList() != nullptr); } void LispIsAtom(LispEnvironment& aEnvironment, int aStackTop) { LispPtr result(ARGUMENT(1)); InternalBoolean(aEnvironment, RESULT, result->String() != nullptr); } void LispIsNumber(LispEnvironment& aEnvironment, int aStackTop) { LispPtr result(ARGUMENT(1)); InternalBoolean(aEnvironment, RESULT, result->Number(aEnvironment.Precision()) != nullptr); } void LispIsInteger(LispEnvironment& aEnvironment, int aStackTop) { LispPtr result(ARGUMENT(1)); BigNumber* num(result->Number(aEnvironment.Precision())); InternalBoolean(aEnvironment, RESULT, num && num->IsInt()); } void LispIsList(LispEnvironment& aEnvironment, int aStackTop) { LispPtr result(ARGUMENT(1)); InternalBoolean(aEnvironment, RESULT, InternalIsList(aEnvironment, result)); } void LispIsString(LispEnvironment& aEnvironment, int aStackTop) { LispPtr result(ARGUMENT(1)); InternalBoolean(aEnvironment, RESULT, InternalIsString(result->String())); } void LispIsBound(LispEnvironment& aEnvironment, int aStackTop) { const LispString* str = ARGUMENT(1)->String(); if (str) { LispPtr val; aEnvironment.GetVariable(str, val); if (!!val) { InternalTrue(aEnvironment, RESULT); return; } } InternalFalse(aEnvironment, RESULT); } void LispIf(LispEnvironment& aEnvironment, int aStackTop) { int nrArguments = InternalListLength(ARGUMENT(0)); if (nrArguments != 3 && nrArguments != 4) { ShowStack(aEnvironment); throw LispErrWrongNumberOfArgs(); } LispPtr predicate; InternalEval(aEnvironment, predicate, ARGUMENT(1)); if (IsTrue(aEnvironment, predicate)) { InternalEval(aEnvironment, RESULT, Argument(ARGUMENT(0), 2)); } else { CheckArg(IsFalse(aEnvironment, predicate), 1, aEnvironment, aStackTop); if (nrArguments == 4) InternalEval(aEnvironment, RESULT, Argument(ARGUMENT(0), 3)); else InternalFalse(aEnvironment, RESULT); } } void LispRetract(LispEnvironment& aEnvironment, int aStackTop) { // Get operator LispPtr evaluated(ARGUMENT(1)); CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const LispString* oper = SymbolName(aEnvironment, *orig); LispPtr arity(ARGUMENT(2)); CheckArg(arity->String(), 2, aEnvironment, aStackTop); int ar = InternalAsciiToInt(*arity->String()); aEnvironment.Retract(oper, ar); InternalTrue(aEnvironment, RESULT); } void YacasBuiltinPrecisionSet(LispEnvironment& aEnvironment, int aStackTop) { LispPtr index(ARGUMENT(1)); CheckArg(index, 1, aEnvironment, aStackTop); CheckArg(index->String(), 1, aEnvironment, aStackTop); int ind = InternalAsciiToInt(*index->String()); CheckArg(ind > 0, 1, aEnvironment, aStackTop); aEnvironment.SetPrecision(ind); InternalTrue(aEnvironment, RESULT); } void LispDefaultDirectory(LispEnvironment& aEnvironment, int aStackTop) { // Get file name CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); aEnvironment.iInputDirectories.push_back(InternalUnstringify(*orig)); InternalTrue(aEnvironment, RESULT); } void LispFromFile(LispEnvironment& aEnvironment, int aStackTop) { CheckSecure(aEnvironment, aStackTop); LispPtr evaluated; InternalEval(aEnvironment, evaluated, ARGUMENT(1)); // Get file name CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const std::string fname = orig->substr(1, orig->length() - 2); InputStatus oldstatus = aEnvironment.iInputStatus; aEnvironment.iInputStatus.SetTo(fname); // Open file LispLocalFile localFP( aEnvironment, fname, true, aEnvironment.iInputDirectories); if (!localFP.stream.is_open()) { ShowStack(aEnvironment); throw LispErrFileNotFound(); } StdFileInput newInput(localFP, aEnvironment.iInputStatus); LispLocalInput localInput(aEnvironment, &newInput); // Evaluate the body InternalEval(aEnvironment, RESULT, ARGUMENT(2)); aEnvironment.iInputStatus.RestoreFrom(oldstatus); // Return the result } void LispFromString(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated; InternalEval(aEnvironment, evaluated, ARGUMENT(1)); // Get file name CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const std::string oper = InternalUnstringify(*orig); InputStatus oldstatus = aEnvironment.iInputStatus; aEnvironment.iInputStatus.SetTo("String"); StringInput newInput(oper, aEnvironment.iInputStatus); LispLocalInput localInput(aEnvironment, &newInput); // Evaluate the body InternalEval(aEnvironment, RESULT, ARGUMENT(2)); aEnvironment.iInputStatus.RestoreFrom(oldstatus); // Return the result } void LispRead(LispEnvironment& aEnvironment, int aStackTop) { LispTokenizer& tok = *aEnvironment.iCurrentTokenizer; InfixParser parser(tok, *aEnvironment.CurrentInput(), aEnvironment, aEnvironment.PreFix(), aEnvironment.InFix(), aEnvironment.PostFix(), aEnvironment.Bodied()); // Read expression parser.Parse(RESULT); } void LispReadToken(LispEnvironment& aEnvironment, int aStackTop) { LispTokenizer& tok = *aEnvironment.iCurrentTokenizer; const LispString* result = aEnvironment.HashTable().LookUp( tok.NextToken(*aEnvironment.CurrentInput())); if (result->empty()) { RESULT = aEnvironment.iEndOfFile->Copy(); return; } RESULT = LispAtom::New(aEnvironment, *result); } void LispToFile(LispEnvironment& aEnvironment, int aStackTop) { CheckSecure(aEnvironment, aStackTop); LispPtr evaluated; InternalEval(aEnvironment, evaluated, ARGUMENT(1)); // Get file name CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const std::string oper = InternalUnstringify(*orig); // Open file for writing LispLocalFile localFP( aEnvironment, oper, false, aEnvironment.iInputDirectories); if (!localFP.stream.is_open()) { ShowStack(aEnvironment); throw LispErrFileNotFound(); } LispLocalOutput localOutput(aEnvironment, localFP.stream); // Evaluate the body InternalEval(aEnvironment, RESULT, ARGUMENT(2)); // Return the result } void LispCheck(LispEnvironment& aEnvironment, int aStackTop) { LispPtr pred; InternalEval(aEnvironment, pred, ARGUMENT(1)); if (!IsTrue(aEnvironment, pred)) { LispPtr evaluated; InternalEval(aEnvironment, evaluated, ARGUMENT(2)); CheckArgIsString(evaluated, 2, aEnvironment, aStackTop); ShowStack(aEnvironment); throw LispErrUser(*evaluated->String()); } RESULT = pred; } void LispTrapError(LispEnvironment& aEnvironment, int aStackTop) { try { InternalEval(aEnvironment, RESULT, ARGUMENT(1)); } catch (const LispError& error) { HandleError(error, aEnvironment, aEnvironment.iErrorOutput); } if (!aEnvironment.iErrorOutput.str().empty()) { InternalEval(aEnvironment, RESULT, ARGUMENT(2)); aEnvironment.iErrorOutput.clear(); aEnvironment.iErrorOutput.str(""); } } void LispGetCoreError(LispEnvironment& aEnvironment, int aStackTop) { RESULT = LispAtom::New(aEnvironment, stringify(aEnvironment.iErrorOutput.str())); } void LispSystemCall(LispEnvironment& aEnvironment, int aStackTop) { CheckSecure(aEnvironment, aStackTop); LispPtr result(ARGUMENT(1)); CheckArgIsString(1, aEnvironment, aStackTop); const std::string command = InternalUnstringify(*result->String()); // we would like to pass the exit code back to Yacas. Right now, let's pass // True/False according to whether the exit code is 0 or not. InternalBoolean(aEnvironment, RESULT, system(command.c_str()) == 0); } void LispSystemName(LispEnvironment& aEnvironment, int aStackTop) { const char* s = "Unknown"; #if defined(_WIN32) s = "Windows"; #elif defined(__APPLE__) s = "MacOSX"; #elif defined(__linux__) s = "Linux"; #endif RESULT = LispAtom::New(aEnvironment, stringify(s)); } void LispMaxEvalDepth(LispEnvironment& aEnvironment, int aStackTop) { LispPtr index(ARGUMENT(1)); CheckArg(index, 1, aEnvironment, aStackTop); CheckArg(index->String(), 1, aEnvironment, aStackTop); int ind = InternalAsciiToInt(*index->String()); aEnvironment.iMaxEvalDepth = ind; InternalTrue(aEnvironment, RESULT); } void LispDefLoad(LispEnvironment& aEnvironment, int aStackTop) { CheckSecure(aEnvironment, aStackTop); LispPtr evaluated(ARGUMENT(1)); // Get file name CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); LoadDefFile(aEnvironment, *orig); InternalTrue(aEnvironment, RESULT); } void LispUse(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); // Get file name CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); InternalUse(aEnvironment, *orig); InternalTrue(aEnvironment, RESULT); } void LispRightAssociative(LispEnvironment& aEnvironment, int aStackTop) { // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); LispOperators::iterator opi = aEnvironment.InFix().find(SymbolName(aEnvironment, *orig)); if (opi == aEnvironment.InFix().end()) throw LispErrNotAnInFixOperator(); opi->second.SetRightAssociative(); InternalTrue(aEnvironment, RESULT); } void LispLeftPrecedence(LispEnvironment& aEnvironment, int aStackTop) { // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); LispPtr index; InternalEval(aEnvironment, index, ARGUMENT(2)); CheckArg(index, 2, aEnvironment, aStackTop); CheckArg(index->String(), 2, aEnvironment, aStackTop); int ind = InternalAsciiToInt(*index->String()); LispOperators::iterator opi = aEnvironment.InFix().find(SymbolName(aEnvironment, *orig)); if (opi == aEnvironment.InFix().end()) throw LispErrNotAnInFixOperator(); opi->second.SetLeftPrecedence(ind); InternalTrue(aEnvironment, RESULT); } void LispRightPrecedence(LispEnvironment& aEnvironment, int aStackTop) { // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); LispPtr index; InternalEval(aEnvironment, index, ARGUMENT(2)); CheckArg(index, 2, aEnvironment, aStackTop); CheckArg(index->String(), 2, aEnvironment, aStackTop); int ind = InternalAsciiToInt(*index->String()); LispOperators::iterator opi = aEnvironment.InFix().find(SymbolName(aEnvironment, *orig)); if (opi == aEnvironment.InFix().end()) throw LispErrNotAnInFixOperator(); opi->second.SetRightPrecedence(ind); InternalTrue(aEnvironment, RESULT); } static LispInFixOperator* OperatorInfo(LispEnvironment& aEnvironment, int aStackTop, LispOperators& aOperators) { // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); LispPtr evaluated(ARGUMENT(1)); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const LispOperators::iterator opi = aOperators.find(SymbolName(aEnvironment, *orig)); if (opi != aOperators.end()) return &opi->second; return nullptr; } void LispIsInFix(LispEnvironment& aEnvironment, int aStackTop) { LispInFixOperator* op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.InFix()); InternalBoolean(aEnvironment, RESULT, op != nullptr); } void LispIsBodied(LispEnvironment& aEnvironment, int aStackTop) { LispInFixOperator* op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.Bodied()); InternalBoolean(aEnvironment, RESULT, op != nullptr); } void LispGetPrecedence(LispEnvironment& aEnvironment, int aStackTop) { LispInFixOperator* op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.InFix()); if (!op) { // also need to check for a postfix or prefix operator op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PreFix()); if (!op) { op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PostFix()); if (!op) { // or maybe it's a bodied function op = OperatorInfo( aEnvironment, aStackTop, aEnvironment.Bodied()); if (!op) { ShowStack(aEnvironment); throw LispErrIsNotInFix(); } } } } RESULT = LispAtom::New(aEnvironment, std::to_string(op->iPrecedence)); } void LispGetLeftPrecedence(LispEnvironment& aEnvironment, int aStackTop) { LispInFixOperator* op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.InFix()); if (!op) { // infix and postfix operators have left precedence op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PostFix()); if (!op) { ShowStack(aEnvironment); throw LispErrIsNotInFix(); } } RESULT = LispAtom::New(aEnvironment, std::to_string(op->iLeftPrecedence)); } void LispGetRightPrecedence(LispEnvironment& aEnvironment, int aStackTop) { LispInFixOperator* op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.InFix()); if (!op) { // bodied, infix and prefix operators have right precedence op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PreFix()); if (!op) { // or maybe it's a bodied function op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.Bodied()); if (!op) { ShowStack(aEnvironment); throw LispErrIsNotInFix(); } } } RESULT = LispAtom::New(aEnvironment, std::to_string(op->iRightPrecedence)); } void LispIsPreFix(LispEnvironment& aEnvironment, int aStackTop) { LispInFixOperator* op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PreFix()); InternalBoolean(aEnvironment, RESULT, op != nullptr); } void LispIsPostFix(LispEnvironment& aEnvironment, int aStackTop) { LispInFixOperator* op = OperatorInfo(aEnvironment, aStackTop, aEnvironment.PostFix()); InternalBoolean(aEnvironment, RESULT, op != nullptr); } void YacasBuiltinPrecisionGet(LispEnvironment& aEnvironment, int aStackTop) { RESULT = LispAtom::New(aEnvironment, std::to_string(aEnvironment.Precision())); } void LispToString(LispEnvironment& aEnvironment, int aStackTop) { std::ostringstream os; LispLocalOutput localOutput(aEnvironment, os); // Evaluate the body InternalEval(aEnvironment, RESULT, ARGUMENT(1)); // Return the result RESULT = LispAtom::New(aEnvironment, stringify(os.str())); } void LispToStdout(LispEnvironment& aEnvironment, int aStackTop) { LispLocalOutput localOutput(aEnvironment, *aEnvironment.iInitialOutput); // Evaluate the body InternalEval(aEnvironment, RESULT, ARGUMENT(1)); } void LispSecure(LispEnvironment& aEnvironment, int aStackTop) { LispSecureFrame security(aEnvironment); InternalEval(aEnvironment, RESULT, ARGUMENT(1)); } void LispFindFile(LispEnvironment& aEnvironment, int aStackTop) { CheckSecure(aEnvironment, aStackTop); LispPtr evaluated(ARGUMENT(1)); // Get file name CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const std::string oper = InternalUnstringify(*orig); const std::string path = InternalFindFile(oper, aEnvironment.iInputDirectories); RESULT = LispAtom::New(aEnvironment, stringify(path)); } void LispIsGeneric(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); InternalBoolean(aEnvironment, RESULT, evaluated->Generic() != nullptr); } void LispGenericTypeName(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); CheckArg(evaluated, 1, aEnvironment, aStackTop); const char* name = evaluated->Generic()->TypeName(); RESULT = (LispAtom::New(aEnvironment, name)); } void GenArrayCreate(LispEnvironment& aEnvironment, int aStackTop) { LispPtr sizearg(ARGUMENT(1)); CheckArg(sizearg, 1, aEnvironment, aStackTop); CheckArg(sizearg->String(), 1, aEnvironment, aStackTop); int size = InternalAsciiToInt(*sizearg->String()); LispPtr initarg(ARGUMENT(2)); ArrayClass* array = new ArrayClass(size, initarg); RESULT = (LispGenericClass::New(array)); } void GenArraySize(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); GenericClass* gen = evaluated->Generic(); ArrayClass* arr = dynamic_cast(gen); CheckArg(arr, 1, aEnvironment, aStackTop); RESULT = LispAtom::New(aEnvironment, std::to_string(arr->Size())); } void GenArrayGet(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); GenericClass* gen = evaluated->Generic(); ArrayClass* arr = dynamic_cast(gen); CheckArg(arr, 1, aEnvironment, aStackTop); LispPtr sizearg(ARGUMENT(2)); CheckArg(sizearg, 2, aEnvironment, aStackTop); CheckArg(sizearg->String(), 2, aEnvironment, aStackTop); int size = InternalAsciiToInt(*sizearg->String()); CheckArg(size > 0 && static_cast(size) <= arr->Size(), 2, aEnvironment, aStackTop); LispObject* object = arr->GetElement(size); RESULT = (object->Copy()); } void GenArraySet(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); GenericClass* gen = evaluated->Generic(); ArrayClass* arr = dynamic_cast(gen); CheckArg(arr, 1, aEnvironment, aStackTop); LispPtr sizearg(ARGUMENT(2)); CheckArg(sizearg, 2, aEnvironment, aStackTop); CheckArg(sizearg->String(), 2, aEnvironment, aStackTop); int size = InternalAsciiToInt(*sizearg->String()); CheckArg(size > 0 && static_cast(size) <= arr->Size(), 2, aEnvironment, aStackTop); LispPtr obj(ARGUMENT(3)); arr->SetElement(size, obj); InternalTrue(aEnvironment, RESULT); } void GenAssociationCreate(LispEnvironment& aEnvironment, int aStackTop) { AssociationClass* a = new AssociationClass(aEnvironment); RESULT = LispGenericClass::New(a); } void GenAssociationSize(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); GenericClass* gen = evaluated->Generic(); AssociationClass* a = dynamic_cast(gen); CheckArg(a, 1, aEnvironment, aStackTop); RESULT = LispAtom::New(aEnvironment, std::to_string(a->Size())); } void GenAssociationContains(LispEnvironment& aEnvironment, int aStackTop) { LispPtr p(ARGUMENT(1)); GenericClass* gen = p->Generic(); AssociationClass* a = dynamic_cast(gen); CheckArg(a, 1, aEnvironment, aStackTop); LispPtr k(ARGUMENT(2)); if (a->GetElement(k)) InternalTrue(aEnvironment, RESULT); else InternalFalse(aEnvironment, RESULT); } void GenAssociationGet(LispEnvironment& aEnvironment, int aStackTop) { LispPtr p(ARGUMENT(1)); GenericClass* gen = p->Generic(); AssociationClass* a = dynamic_cast(gen); CheckArg(a, 1, aEnvironment, aStackTop); LispPtr k(ARGUMENT(2)); LispObject* v = a->GetElement(k); if (v) RESULT = v->Copy(); else RESULT = LispAtom::New(aEnvironment, "Undefined"); } void GenAssociationSet(LispEnvironment& aEnvironment, int aStackTop) { LispPtr p(ARGUMENT(1)); GenericClass* gen = p->Generic(); AssociationClass* a = dynamic_cast(gen); CheckArg(a, 1, aEnvironment, aStackTop); LispPtr k(ARGUMENT(2)); LispPtr v(ARGUMENT(3)); a->SetElement(k, v); InternalTrue(aEnvironment, RESULT); } void GenAssociationDrop(LispEnvironment& aEnvironment, int aStackTop) { LispPtr p(ARGUMENT(1)); GenericClass* gen = p->Generic(); AssociationClass* a = dynamic_cast(gen); CheckArg(a, 1, aEnvironment, aStackTop); LispPtr k(ARGUMENT(2)); if (a->DropElement(k)) InternalTrue(aEnvironment, RESULT); else InternalFalse(aEnvironment, RESULT); } void GenAssociationKeys(LispEnvironment& aEnvironment, int aStackTop) { LispPtr p(ARGUMENT(1)); GenericClass* gen = p->Generic(); AssociationClass* a = dynamic_cast(gen); CheckArg(a, 1, aEnvironment, aStackTop); RESULT = a->Keys(); } void GenAssociationToList(LispEnvironment& aEnvironment, int aStackTop) { LispPtr p(ARGUMENT(1)); GenericClass* gen = p->Generic(); AssociationClass* a = dynamic_cast(gen); CheckArg(a, 1, aEnvironment, aStackTop); RESULT = a->ToList(); } void GenAssociationHead(LispEnvironment& aEnvironment, int aStackTop) { LispPtr p(ARGUMENT(1)); GenericClass* gen = p->Generic(); AssociationClass* a = dynamic_cast(gen); CheckArg(a, 1, aEnvironment, aStackTop); CheckArg(a->Size(), 1, aEnvironment, aStackTop); RESULT = a->Head(); } void LispCustomEval(LispEnvironment& aEnvironment, int aStackTop) { if (aEnvironment.iDebugger) delete aEnvironment.iDebugger; aEnvironment.iDebugger = new DefaultDebugger(ARGUMENT(1), ARGUMENT(2), ARGUMENT(3)); LispLocalEvaluator local(aEnvironment, new TracedEvaluator); aEnvironment.iDebugger->Start(); InternalEval(aEnvironment, RESULT, ARGUMENT(4)); aEnvironment.iDebugger->Finish(); delete aEnvironment.iDebugger; aEnvironment.iDebugger = nullptr; } void LispCustomEvalExpression(LispEnvironment& aEnvironment, int aStackTop) { if (!aEnvironment.iDebugger) throw LispErrGeneric( "Trying to get CustomEval results while not in custom evaluation"); RESULT = (aEnvironment.iDebugger->iTopExpr); } void LispCustomEvalResult(LispEnvironment& aEnvironment, int aStackTop) { if (!aEnvironment.iDebugger) throw LispErrGeneric( "Trying to get CustomEval results while not in custom evaluation"); RESULT = (aEnvironment.iDebugger->iTopResult); } void LispCustomEvalLocals(LispEnvironment& aEnvironment, int aStackTop) { aEnvironment.CurrentLocals(RESULT); } void LispCustomEvalStop(LispEnvironment& aEnvironment, int aStackTop) { if (!aEnvironment.iDebugger) throw LispErrGeneric( "Trying to get CustomEval results while not in custom evaluation"); aEnvironment.iDebugger->iStopped = true; InternalTrue(aEnvironment, RESULT); } void LispTraceStack(LispEnvironment& aEnvironment, int aStackTop) { LispLocalEvaluator local(aEnvironment, new TracedStackEvaluator); InternalEval(aEnvironment, RESULT, ARGUMENT(1)); } void LispReadLisp(LispEnvironment& aEnvironment, int aStackTop) { LispTokenizer& tok = *aEnvironment.iCurrentTokenizer; LispParser parser(tok, *aEnvironment.CurrentInput(), aEnvironment); // Read expression parser.Parse(RESULT); } void LispReadLispListed(LispEnvironment& aEnvironment, int aStackTop) { LispTokenizer& tok = *aEnvironment.iCurrentTokenizer; LispParser parser(tok, *aEnvironment.CurrentInput(), aEnvironment); parser.iListed = true; // Read expression parser.Parse(RESULT); } void LispTraceRule(LispEnvironment& aEnvironment, int aStackTop) { LispPtr* ptr = ARGUMENT(0)->Nixed()->SubList(); LispUserFunction* userfunc = nullptr; if (ptr) userfunc = GetUserFunction(aEnvironment, ptr); LispLocalTrace trace(userfunc); InternalEval(aEnvironment, RESULT, ARGUMENT(2)); } void LispType(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); LispPtr* subList = evaluated->SubList(); LispObject* head = nullptr; if (!subList) { goto EMPTY; } head = (*subList); if (!head->String()) goto EMPTY; RESULT = LispAtom::New( aEnvironment, *aEnvironment.HashTable().LookUp(stringify(*head->String()))); return; EMPTY: RESULT = LispAtom::New(aEnvironment, "\"\""); return; } void YacasStringMidGet(LispEnvironment& aEnvironment, int aStackTop) { CheckArgIsString(3, aEnvironment, aStackTop); LispPtr evaluated(ARGUMENT(3)); const LispString* orig = evaluated->String(); LispPtr index(ARGUMENT(1)); CheckArg(index, 1, aEnvironment, aStackTop); CheckArg(index->String(), 1, aEnvironment, aStackTop); const int sfrom = InternalAsciiToInt(*index->String()); CheckArg(sfrom > 0, 1, aEnvironment, aStackTop); const std::size_t from = sfrom; index = (ARGUMENT(2)); CheckArg(index, 2, aEnvironment, aStackTop); CheckArg(index->String(), 2, aEnvironment, aStackTop); const int scount = InternalAsciiToInt(*index->String()); const std::size_t count = scount; std::string str = "\""; // FIXME: it's actually the set of args which is wrong, not the specific one CheckArg(from + count < orig->size(), 1, aEnvironment, aStackTop); for (std::size_t i = from; i < from + count; ++i) str.push_back((*orig)[i]); str.push_back('\"'); RESULT = LispAtom::New(aEnvironment, str); } void YacasStringMidSet(LispEnvironment& aEnvironment, int aStackTop) { CheckArgIsString(3, aEnvironment, aStackTop); LispPtr evaluated(ARGUMENT(3)); const LispString* orig = evaluated->String(); LispPtr index(ARGUMENT(1)); CheckArg(index, 1, aEnvironment, aStackTop); CheckArg(index->String(), 1, aEnvironment, aStackTop); const int sfrom = InternalAsciiToInt(*index->String()); CheckArg(sfrom > 0, 1, aEnvironment, aStackTop); const std::size_t from = sfrom; LispPtr ev2(ARGUMENT(2)); CheckArgIsString(2, aEnvironment, aStackTop); const LispString* replace = ev2->String(); std::string str(*orig); const std::size_t count = replace->size(); // FIXME: it's actually the set of args which is wrong, not the specific one CheckArg(from + count < orig->size() + 2, 1, aEnvironment, aStackTop); for (std::size_t i = 0; i < count - 2; ++i) str[i + from] = (*replace)[i + 1]; RESULT = LispAtom::New(aEnvironment, str); } void LispFindFunction(LispEnvironment& aEnvironment, int aStackTop) { CheckSecure(aEnvironment, aStackTop); LispPtr evaluated(ARGUMENT(1)); // Get file name CheckArg(evaluated, 1, aEnvironment, aStackTop); const LispString* orig = evaluated->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const std::string oper = InternalUnstringify(*orig); LispMultiUserFunction* multiUserFunc = aEnvironment.MultiUserFunction(aEnvironment.HashTable().LookUp(oper)); if (multiUserFunc) { LispDefFile* def = multiUserFunc->iFileToOpen; if (def) { RESULT = LispAtom::New(aEnvironment, def->FileName()); return; } } RESULT = LispAtom::New(aEnvironment, "\"\""); } /// Corresponds to the Yacas function \c PatternCreate . /// This function constructs a new PatternClass, and puts it in a new /// LispGenericObject. The result is set to this LispGenericObject. void GenPatternCreate(LispEnvironment& aEnvironment, int aStackTop) { LispPtr pattern(ARGUMENT(1)); LispPtr postpredicate(ARGUMENT(2)); LispIterator iter(pattern); LispObject* pObj = iter.getObj(); CheckArg(pObj, 1, aEnvironment, aStackTop); LispPtr* pPtr = pObj->SubList(); CheckArg(pPtr, 1, aEnvironment, aStackTop); iter = *pPtr; CheckArg(iter.getObj(), 1, aEnvironment, aStackTop); ++iter; YacasPatternPredicateBase* matcher = new YacasPatternPredicateBase(aEnvironment, *iter, postpredicate); PatternClass* p = new PatternClass(matcher); RESULT = (LispGenericClass::New(p)); } void GenPatternMatches(LispEnvironment& aEnvironment, int aStackTop) { LispPtr pattern(ARGUMENT(1)); GenericClass* gen = pattern->Generic(); PatternClass* pat = dynamic_cast(gen); CheckArg(pat, 1, aEnvironment, aStackTop); LispPtr list(ARGUMENT(2)); LispIterator iter(list); LispObject* pObj = iter.getObj(); CheckArg(pObj, 2, aEnvironment, aStackTop); LispPtr* pPtr = pObj->SubList(); CheckArg(pPtr, 2, aEnvironment, aStackTop); iter = *pPtr; CheckArg(iter.getObj(), 2, aEnvironment, aStackTop); ++iter; CheckArg(iter.getObj(), 2, aEnvironment, aStackTop); bool matches = pat->Matches(aEnvironment, *iter); InternalBoolean(aEnvironment, RESULT, matches); } void LispRuleBaseDefined(LispEnvironment& aEnvironment, int aStackTop) { LispPtr name(ARGUMENT(1)); const LispString* orig = name->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const std::string oper = InternalUnstringify(*orig); LispPtr sizearg(ARGUMENT(2)); CheckArg(sizearg, 2, aEnvironment, aStackTop); CheckArg(sizearg->String(), 2, aEnvironment, aStackTop); int arity = InternalAsciiToInt(*sizearg->String()); LispUserFunction* userFunc = aEnvironment.UserFunction(aEnvironment.HashTable().LookUp(oper), arity); InternalBoolean(aEnvironment, RESULT, !!userFunc); } void LispDefLoadFunction(LispEnvironment& aEnvironment, int aStackTop) { LispPtr name(ARGUMENT(1)); const LispString* orig = name->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const std::string oper = InternalUnstringify(*orig); LispMultiUserFunction* multiUserFunc = aEnvironment.MultiUserFunction(aEnvironment.HashTable().LookUp(oper)); if (multiUserFunc) { if (multiUserFunc->iFileToOpen != nullptr) { LispDefFile* def = multiUserFunc->iFileToOpen; if (!def->IsLoaded()) { multiUserFunc->iFileToOpen = nullptr; // InternalUse(aEnvironment, def->FileName()); } } } InternalTrue(aEnvironment, RESULT); } void LispRuleBaseArgList(LispEnvironment& aEnvironment, int aStackTop) { LispPtr name(ARGUMENT(1)); const LispString* orig = name->String(); CheckArg(orig, 1, aEnvironment, aStackTop); const std::string oper = InternalUnstringify(*orig); LispPtr sizearg(ARGUMENT(2)); CheckArg(sizearg, 2, aEnvironment, aStackTop); CheckArg(sizearg->String(), 2, aEnvironment, aStackTop); int arity = InternalAsciiToInt(*sizearg->String()); LispUserFunction* userFunc = aEnvironment.UserFunction(aEnvironment.HashTable().LookUp(oper), arity); CheckArg(userFunc, 1, aEnvironment, aStackTop); const LispPtr& list = userFunc->ArgList(); LispPtr head(aEnvironment.iList->Copy()); head->Nixed() = (list); RESULT = (LispSubList::New(head)); } static void InternalNewRulePattern(LispEnvironment& aEnvironment, int aStackTop, bool aMacroMode) { int arity; int precedence; LispPtr ar; LispPtr pr; LispPtr predicate; LispPtr body; // Get operator CheckArg(ARGUMENT(1), 1, aEnvironment, aStackTop); const LispString* orig = ARGUMENT(1)->String(); CheckArg(orig, 1, aEnvironment, aStackTop); ar = (ARGUMENT(2)); pr = (ARGUMENT(3)); predicate = (ARGUMENT(4)); body = (ARGUMENT(5)); // The arity CheckArg(ar, 2, aEnvironment, aStackTop); CheckArg(ar->String(), 2, aEnvironment, aStackTop); arity = InternalAsciiToInt(*ar->String()); // The precedence CheckArg(ar, 3, aEnvironment, aStackTop); CheckArg(ar->String(), 3, aEnvironment, aStackTop); precedence = InternalAsciiToInt(*pr->String()); // Finally define the rule base aEnvironment.DefineRulePattern( SymbolName(aEnvironment, *orig), arity, precedence, predicate, body); // Return true InternalTrue(aEnvironment, RESULT); } void LispNewRulePattern(LispEnvironment& aEnvironment, int aStackTop) { InternalNewRulePattern(aEnvironment, aStackTop, false); } void LispMacroNewRulePattern(LispEnvironment& aEnvironment, int aStackTop) { InternalNewRulePattern(aEnvironment, aStackTop, true); } ================================================ FILE: cyacas/libyacas/src/mathcommands2.cpp ================================================ #include "yacas/arrayclass.h" #include "yacas/errors.h" #include "yacas/infixparser.h" #include "yacas/lispatom.h" #include "yacas/lispenvironment.h" #include "yacas/lisperror.h" #include "yacas/lispeval.h" #include "yacas/lispparser.h" #include "yacas/lispuserfunc.h" #include "yacas/mathuserfunc.h" #include "yacas/numbers.h" #include "yacas/patternclass.h" #include "yacas/platmath.h" #include "yacas/standard.h" #include "yacas/substitute.h" #include #define InternalEval aEnvironment.iEvaluator->Eval #define RESULT aEnvironment.iStack[aStackTop] #define ARGUMENT(i) aEnvironment.iStack[aStackTop + i] void LispSubst(LispEnvironment& aEnvironment, int aStackTop) { LispPtr from(ARGUMENT(1)); LispPtr to(ARGUMENT(2)); LispPtr body(ARGUMENT(3)); SubstBehaviour behaviour(aEnvironment, from, to); InternalSubstitute(RESULT, body, behaviour); } void LispLocalSymbols(LispEnvironment& aEnvironment, int aStackTop) { int nrArguments = InternalListLength(ARGUMENT(0)); int nrSymbols = nrArguments - 2; std::vector names(nrSymbols); std::vector localnames(nrSymbols); int uniquenumber = aEnvironment.GetUniqueId(); int i; for (i = 0; i < nrSymbols; i++) { const LispString* atomname = Argument(ARGUMENT(0), i + 1)->String(); CheckArg(atomname, i + 1, aEnvironment, aStackTop); names[i] = atomname; std::string newname = "$"; newname.append(*atomname); newname.append(std::to_string(uniquenumber)); localnames[i] = aEnvironment.HashTable().LookUp(newname); } LocalSymbolBehaviour behaviour( aEnvironment, std::move(names), std::move(localnames)); LispPtr result; InternalSubstitute( result, Argument(ARGUMENT(0), nrArguments - 1), behaviour); InternalEval(aEnvironment, RESULT, result); } void LispCharString(LispEnvironment& aEnvironment, int aStackTop) { const LispString* str = ARGUMENT(1)->String(); CheckArg(str, 2, aEnvironment, aStackTop); CheckArg(IsNumber(*str, false), 2, aEnvironment, aStackTop); int asciiCode = InternalAsciiToInt(*str); char ascii[4]; ascii[0] = '\"'; ascii[1] = (char)asciiCode; ascii[2] = '\"'; ascii[3] = '\0'; RESULT = (LispAtom::New(aEnvironment, ascii)); } void LispInDebugMode(LispEnvironment& aEnvironment, int aStackTop) { InternalFalse(aEnvironment, RESULT); } void LispDebugFile(LispEnvironment& aEnvironment, int aStackTop) { throw LispErrGeneric("Cannot call DebugFile in non-debug version of Yacas"); } void LispDebugLine(LispEnvironment& aEnvironment, int aStackTop) { throw LispErrGeneric("Cannot call DebugLine in non-debug version of Yacas"); } ================================================ FILE: cyacas/libyacas/src/mathcommands3.cpp ================================================ #include "yacas/arrayclass.h" #include "yacas/errors.h" #include "yacas/infixparser.h" #include "yacas/lispatom.h" #include "yacas/lispenvironment.h" #include "yacas/lisperror.h" #include "yacas/lispeval.h" #include "yacas/lispparser.h" #include "yacas/lispuserfunc.h" #include "yacas/mathuserfunc.h" #include "yacas/numbers.h" #include "yacas/patcher.h" #include "yacas/patternclass.h" #include "yacas/platfileio.h" #include "yacas/platmath.h" #include "yacas/standard.h" #include "yacas/string_utils.h" #include "yacas/stringio.h" #include "yacas/substitute.h" #include #include "yacas/yacas_version.h" #include #include #define InternalEval aEnvironment.iEvaluator->Eval #define RESULT aEnvironment.iStack[aStackTop] #define ARGUMENT(i) aEnvironment.iStack[aStackTop + i] /// Construct a BigNumber from one of the arguments. /// \param x (on output) the constructed bignumber /// \param aEnvironment the current environment /// \param aStackTop the index of the top of the stack /// \param aArgNr the index of the argument to be converted void GetNumber(RefPtr& x, LispEnvironment& aEnvironment, int aStackTop, int aArgNr) { x = ARGUMENT(aArgNr)->Number(aEnvironment.Precision()); CheckArg(x, aArgNr, aEnvironment, aStackTop); } // FIXME remove these void LispArithmetic2(LispEnvironment& aEnvironment, int aStackTop, LispObject* (*func)(LispObject* f1, LispObject* f2, LispEnvironment& aEnvironment, int aPrecision), bool arbbase = false); void LispArithmetic1(LispEnvironment& aEnvironment, int aStackTop, LispObject* (*func)(LispObject* f1, LispEnvironment& aEnvironment, int aPrecision)); // FIXME remove these void LispArithmetic1(LispEnvironment& aEnvironment, int aStackTop, LispObject* (*func)(LispObject* f1, LispEnvironment& aEnvironment, int aPrecision)) { CheckArg(ARGUMENT(1)->Number(0), 1, aEnvironment, aStackTop); RESULT = (func(ARGUMENT(1), aEnvironment, aEnvironment.Precision())); } // FIXME remove these void LispArithmetic2(LispEnvironment& aEnvironment, int aStackTop, LispObject* (*func)(LispObject* f1, LispObject* f2, LispEnvironment& aEnvironment, int aPrecision), bool arbbase) { if (!arbbase) { CheckArg(ARGUMENT(1)->Number(0), 1, aEnvironment, aStackTop); CheckArg(ARGUMENT(2)->Number(0), 2, aEnvironment, aStackTop); } RESULT = (func( ARGUMENT(1), ARGUMENT(2), aEnvironment, aEnvironment.Precision())); } void LispDumpBigNumberDebugInfo(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); x->DumpDebugInfo(aEnvironment.CurrentOutput()); InternalTrue(aEnvironment, RESULT); } void LispMultiply(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; RefPtr y; GetNumber(x, aEnvironment, aStackTop, 1); GetNumber(y, aEnvironment, aStackTop, 2); BigNumber* z = new BigNumber("0", aEnvironment.BinaryPrecision()); z->Precision(aEnvironment.BinaryPrecision()); z->Multiply(*x, *y, aEnvironment.BinaryPrecision()); RESULT = new LispNumber(z); return; } // TODO we need to have Gcd in BigNumber! void LispGcd(LispEnvironment& aEnvironment, int aStackTop) { CheckArg(ARGUMENT(1)->Number(0), 1, aEnvironment, aStackTop); CheckArg(ARGUMENT(2)->Number(0), 2, aEnvironment, aStackTop); RESULT = (GcdInteger(ARGUMENT(1), ARGUMENT(2), aEnvironment)); } /// Corresponds to the Yacas function \c MathAdd. /// If called with one argument (unary plus), this argument is /// converted to BigNumber. If called with two arguments (binary plus), /// both argument are converted to a BigNumber, and these are added /// together at the current precision. The sum is returned. /// \sa GetNumber(), BigNumber::Add() void LispAdd(LispEnvironment& aEnvironment, int aStackTop) { int length = InternalListLength(ARGUMENT(0)); if (length == 2) { RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); RESULT = (new LispNumber(x.ptr())); return; } else { RefPtr x; RefPtr y; GetNumber(x, aEnvironment, aStackTop, 1); GetNumber(y, aEnvironment, aStackTop, 2); BigNumber* z = new BigNumber("0", aEnvironment.BinaryPrecision()); z->Precision(aEnvironment.BinaryPrecision()); z->Add(*x.ptr(), *y.ptr(), aEnvironment.BinaryPrecision()); RESULT = (new LispNumber(z)); return; } } void LispSubtract(LispEnvironment& aEnvironment, int aStackTop) { int length = InternalListLength(ARGUMENT(0)); if (length == 2) { RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); BigNumber* z = new BigNumber(*x); z->Negate(*z); RESULT = (new LispNumber(z)); return; } else { RefPtr x; RefPtr y; GetNumber(x, aEnvironment, aStackTop, 1); GetNumber(y, aEnvironment, aStackTop, 2); BigNumber yneg(*y); yneg.Negate(yneg); BigNumber* z = new BigNumber("0", aEnvironment.BinaryPrecision()); z->Precision(aEnvironment.BinaryPrecision()); z->Add(*x, yneg, aEnvironment.BinaryPrecision()); RESULT = (new LispNumber(z)); return; } } void LispDivide(LispEnvironment& aEnvironment, int aStackTop) { // Serge, what was the deal again with divide, floats and integers mixed in // the same function? // yes, divide works differently on integers and on floats -- see new.chapt // -- Serge RefPtr x; RefPtr y; GetNumber(x, aEnvironment, aStackTop, 1); GetNumber(y, aEnvironment, aStackTop, 2); BigNumber* z = new BigNumber("0", aEnvironment.BinaryPrecision()); z->Precision(aEnvironment.BinaryPrecision()); // if both arguments are integers, then BigNumber::Divide would perform an // integer divide, but we want a float divide here. if (x->IsInt() && y->IsInt()) { // why can't we just say BigNumber temp; ? BigNumber tempx(*x); tempx.BecomeFloat(aEnvironment.BinaryPrecision()); // coerce x to float BigNumber tempy(*y); tempy.BecomeFloat(aEnvironment.BinaryPrecision()); // coerce x to float z->Divide(tempx, tempy, aEnvironment.BinaryPrecision()); } else { z->Divide(*x, *y, aEnvironment.BinaryPrecision()); } RESULT = (new LispNumber(z)); return; } #define UNARYFUNCTION(LispName, BigNumName) \ void LispName(LispEnvironment& aEnvironment, int aStackTop) \ { \ RefPtr x; \ GetNumber(x, aEnvironment, aStackTop, 1); \ BigNumber* z = new BigNumber(*x); \ z->BigNumName(*z); \ RESULT = (new LispNumber(z)); \ } #define BINARYFUNCTION(LispName, BigNumName) \ void LispName(LispEnvironment& aEnvironment, int aStackTop) \ { \ RefPtr x; \ RefPtr y; \ GetNumber(x, aEnvironment, aStackTop, 1); \ GetNumber(y, aEnvironment, aStackTop, 2); \ BigNumber* z = new BigNumber("0", 0); \ z->BigNumName(*x, *y); \ RESULT = (new LispNumber(z)); \ } UNARYFUNCTION(LispFloor, Floor) UNARYFUNCTION(LispMathNegate, Negate) /** the macro UNARYFUNCTION(LispFloor, Floor, FloorFloat) is used to help interface Yacas with BigNumber. Suppose we need to access a unary function named 'Floor' in BigNumber and 'LispFloor' here, with 'FloorFloat' the backup function for no BigNumber support. The macro produces the following equivalent code for the unary function: void LispFloor(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; GetNumber(x,aEnvironment, aStackTop, 1); BigNumber *z = new BigNumber(aEnvironment.BinaryPrecision()); z->Floor(*x.Ptr()); RESULT = (new LispNumber(z)); } */ /* FIXME Eventually the BigNumber support will be stable and we can remove old * code and simplify these macros */ /// obtain internal precision data on a number object. void LispGetExactBits(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); BigNumber* z = new BigNumber( std::to_string(x->IsInt() ? x->BitCount() : x->GetPrecision()), aEnvironment.BinaryPrecision()); RESULT = (new LispNumber(z)); } /// set internal precision data on a number object. void LispSetExactBits(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; RefPtr y; GetNumber(x, aEnvironment, aStackTop, 1); GetNumber(y, aEnvironment, aStackTop, 2); BigNumber* z = new BigNumber(*x); // do nothing for integers if (!(z->IsInt())) z->Precision((long)(y->Double())); // segfaults unless y is defined? RESULT = (new LispNumber(z)); } /// obtain the bit count of a number object. void LispBitCount(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); BigNumber* z = new BigNumber(std::to_string(x->BitCount()), aEnvironment.BinaryPrecision()); RESULT = (new LispNumber(z)); } /// obtain the sign of a number object. void LispMathSign(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); BigNumber* z = new BigNumber(std::to_string(x->Sign()), aEnvironment.BinaryPrecision()); RESULT = (new LispNumber(z)); } /// check whether a number object fits into a platform type. void LispMathIsSmall(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); InternalBoolean(aEnvironment, RESULT, x->IsSmall()); } void LispCeil(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); BigNumber* z = new BigNumber("0", aEnvironment.BinaryPrecision()); z->Negate(*x); z->Floor(*z); // danger: possible exception raised in Floor() leads to a // memory leak because z is not destroyed z->Negate(*z); RESULT = (new LispNumber(z)); } void LispAbs(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); BigNumber* z = new BigNumber(*x); if (x->Sign() < 0) z->Negate(*x); RESULT = (new LispNumber(z)); } // BINARYFUNCTION(LispMod, Mod, ModFloat) /* this will be gone */ void LispMod(LispEnvironment& aEnvironment, int aStackTop) { // FIXME LispArithmetic2(aEnvironment, aStackTop, ModFloat); } /* up to here */ void LispDiv(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; RefPtr y; GetNumber(x, aEnvironment, aStackTop, 1); GetNumber(y, aEnvironment, aStackTop, 2); // TODO FIXME: either need to report error that one or both of the arguments // are not integer, or coerce them to integers CheckArg(x->IsInt(), 1, aEnvironment, aStackTop); CheckArg(y->IsInt(), 2, aEnvironment, aStackTop); BigNumber* z = new BigNumber("0", aEnvironment.BinaryPrecision()); z->Precision(aEnvironment.BinaryPrecision()); z->Divide(*x, *y, aEnvironment.BinaryPrecision()); RESULT = (new LispNumber(z)); } void LispPower(LispEnvironment& aEnvironment, int aStackTop) { // FIXME move to scripts LispArithmetic2(aEnvironment, aStackTop, PowerFloat); } void LispFac(LispEnvironment& aEnvironment, int aStackTop) { // FIXME move to scripts LispArithmetic1(aEnvironment, aStackTop, LispFactorial); } // platform functions, taking/returning a platform int/float void LispFastIsPrime(LispEnvironment& aEnvironment, int aStackTop) { // TODO FIXME RefPtr x; GetNumber(x, aEnvironment, aStackTop, 1); long result = primes_table_check((unsigned long)(x->Double())); BigNumber* z = new BigNumber(std::to_string(result), aEnvironment.BinaryPrecision()); RESULT = (new LispNumber(z)); } // define a macro to replace all platform math functions #define PLATFORM_UNARY(LispName, PlatformName, LispBackupName, OldName) \ void LispName(LispEnvironment& aEnvironment, int aStackTop) \ { \ RefPtr x; \ GetNumber(x, aEnvironment, aStackTop, 1); \ std::ostringstream buf; \ buf << std::setprecision(53) << PlatformName(x->Double()); \ BigNumber* z = \ new BigNumber(buf.str(), aEnvironment.BinaryPrecision()); \ RESULT = (new LispNumber(z)); \ } #define PLATFORM_BINARY(LispName, PlatformName, LispBackupName, OldName) \ void LispName(LispEnvironment& aEnvironment, int aStackTop) \ { \ RefPtr x, y; \ GetNumber(x, aEnvironment, aStackTop, 1); \ GetNumber(y, aEnvironment, aStackTop, 2); \ std::ostringstream buf; \ buf << std::setprecision(53) \ << PlatformName(x->Double(), y->Double()); \ BigNumber* z = \ new BigNumber(buf.str(), aEnvironment.BinaryPrecision()); \ RESULT = (new LispNumber(z)); \ } // now we can define all such functions, e.g.: // some or all of these functions should be moved to scripts PLATFORM_UNARY(LispFastArcSin, std::asin, LispArcSin, PlatArcSin) PLATFORM_UNARY(LispFastLog, std::log, LispLn, PlatLn) PLATFORM_BINARY(LispFastPower, std::pow, LispPower, PlatPower) BINARYFUNCTION(LispBitAnd, BitAnd) BINARYFUNCTION(LispBitOr, BitOr) BINARYFUNCTION(LispBitXor, BitXor) /* // BitNot not yet in yacasapi etc. //BINARYFUNCTION(LispBitNot, BitNot, BitNot) */ /* this will be gone */ void LispShiftLeft(LispEnvironment& aEnvironment, int aStackTop) { // FIXME LispArithmetic2(aEnvironment, aStackTop, ShiftLeft); } void LispShiftRight(LispEnvironment& aEnvironment, int aStackTop) { // FIXME LispArithmetic2(aEnvironment, aStackTop, ShiftRight); } /* up to here */ void LispFromBase(LispEnvironment& aEnvironment, int aStackTop) { // Get the base to convert to: // Evaluate first argument, and store result in oper LispPtr oper(ARGUMENT(1)); // Check that result is a number, and that it is in fact an integer RefPtr num; num = oper->Number(aEnvironment.BinaryPrecision()); CheckArg(num, 1, aEnvironment, aStackTop); // check that the base is an integer between 2 and 32 CheckArg(num->IsInt() && num->Double() >= BASE2 && num->Double() <= log2_table_range(), 1, aEnvironment, aStackTop); // Get a short platform integer from the first argument int base = (int)(num->Double()); // Get the number to convert LispPtr fromNum(ARGUMENT(2)); const LispString* str2 = fromNum->String(); CheckArg(str2, 2, aEnvironment, aStackTop); // Added, unquote a string CheckArg(InternalIsString(str2), 2, aEnvironment, aStackTop); str2 = aEnvironment.HashTable().LookUp(str2->substr(1, str2->length() - 2)); // convert using correct base // FIXME: API breach, must pass precision in base digits and not in bits! // if converting an integer, the precision argument is ignored, // but if converting a float, need to use bits_to_digits(BinaryPrecision, // base) BigNumber* z = new BigNumber(*str2, aEnvironment.BinaryPrecision(), base); RESULT = (new LispNumber(z)); } void LispToBase(LispEnvironment& aEnvironment, int aStackTop) { // Get the base to convert to: // Evaluate first argument, and store result in oper LispPtr oper(ARGUMENT(1)); // Check that result is a number, and that it is in fact an integer RefPtr num; num = oper->Number(aEnvironment.BinaryPrecision()); CheckArg(num, 1, aEnvironment, aStackTop); // check that the base is an integer between 2 and 32 CheckArg(num->IsInt() && num->Double() >= BASE2 && num->Double() <= log2_table_range(), 1, aEnvironment, aStackTop); // Get a short platform integer from the first argument int base = (int)(num->Double()); // Get the number to convert RefPtr x; GetNumber(x, aEnvironment, aStackTop, 2); // convert using correct base LispString str; // FIXME: API breach, must pass precision in base digits and not in bits! // if converting an integer, the precision argument is ignored, // but if converting a float, need to use bits_to_digits(BinaryPrecision, // base) x->ToString(str, aEnvironment.BinaryPrecision(), base); // Get unique string from hash table, and create an atom from it. RESULT = LispAtom::New(aEnvironment, stringify(str)); } void LispApplyPure(LispEnvironment& aEnvironment, int aStackTop) { LispPtr oper(ARGUMENT(1)); LispPtr args(ARGUMENT(2)); CheckArg(args->SubList(), 2, aEnvironment, aStackTop); CheckArg(*args->SubList(), 2, aEnvironment, aStackTop); // Apply a pure string if (oper->String()) { InternalApplyString( aEnvironment, RESULT, oper->String(), (*args->SubList())->Nixed()); } else { // Apply a pure function {args,body}. LispPtr args2((*args->SubList())->Nixed()); CheckArg(oper->SubList(), 1, aEnvironment, aStackTop); CheckArg(*oper->SubList(), 1, aEnvironment, aStackTop); InternalApplyPure(oper, args2, RESULT, aEnvironment); } } void YacasPrettyReaderSet(LispEnvironment& aEnvironment, int aStackTop) { int nrArguments = InternalListLength(ARGUMENT(0)); if (nrArguments == 1) { aEnvironment.SetPrettyReader(nullptr); } else { CheckNrArgs(2, ARGUMENT(0), aEnvironment); LispPtr oper(ARGUMENT(0)); oper = oper->Nixed(); // oper.GoNext(); // woof woof woof CheckArgIsString(oper, 1, aEnvironment, aStackTop); aEnvironment.SetPrettyReader(oper->String()); } InternalTrue(aEnvironment, RESULT); } void YacasPrettyReaderGet(LispEnvironment& aEnvironment, int aStackTop) { if (!aEnvironment.PrettyReader()) RESULT = LispAtom::New(aEnvironment, "\"\""); else RESULT = LispAtom::New(aEnvironment, *aEnvironment.PrettyReader()); } void YacasPrettyPrinterSet(LispEnvironment& aEnvironment, int aStackTop) { int nrArguments = InternalListLength(ARGUMENT(0)); if (nrArguments == 1) { aEnvironment.SetPrettyPrinter(nullptr); } else { CheckNrArgs(2, ARGUMENT(0), aEnvironment); LispPtr oper(ARGUMENT(0)); oper = oper->Nixed(); // oper.GoNext(); // woof woof woof CheckArgIsString(oper, 1, aEnvironment, aStackTop); aEnvironment.SetPrettyPrinter(oper->String()); } InternalTrue(aEnvironment, RESULT); } void YacasPrettyPrinterGet(LispEnvironment& aEnvironment, int aStackTop) { if (!aEnvironment.PrettyPrinter()) RESULT = LispAtom::New(aEnvironment, "\"\""); else RESULT = LispAtom::New(aEnvironment, *aEnvironment.PrettyPrinter()); } void LispGarbageCollect(LispEnvironment& aEnvironment, int aStackTop) { aEnvironment.HashTable().GarbageCollect(); InternalTrue(aEnvironment, RESULT); } void LispPatchLoad(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); const LispString* string = evaluated->String(); CheckArg(string, 1, aEnvironment, aStackTop); const std::string fname = InternalUnstringify(*string); InputStatus oldstatus = aEnvironment.iInputStatus; aEnvironment.iInputStatus.SetTo(fname); LispLocalFile localFP( aEnvironment, fname, true, aEnvironment.iInputDirectories); if (!localFP.stream.is_open()) throw LispErrFileNotFound(); std::string content(std::istreambuf_iterator(localFP.stream), std::istreambuf_iterator()); PatchLoad(content, aEnvironment.CurrentOutput(), aEnvironment); aEnvironment.iInputStatus.RestoreFrom(oldstatus); InternalTrue(aEnvironment, RESULT); } void LispPatchString(LispEnvironment& aEnvironment, int aStackTop) { LispPtr evaluated(ARGUMENT(1)); const LispString* string = evaluated->String(); CheckArg(string, 1, aEnvironment, aStackTop); const std::string oper = InternalUnstringify(*string); std::ostringstream os; LispLocalOutput localOutput(aEnvironment, os); PatchLoad(oper, os, aEnvironment); RESULT = LispAtom::New(aEnvironment, stringify(os.str())); } void LispDefaultTokenizer(LispEnvironment& aEnvironment, int aStackTop) { aEnvironment.iCurrentTokenizer = &aEnvironment.iDefaultTokenizer; InternalTrue(aEnvironment, RESULT); } void LispXmlTokenizer(LispEnvironment& aEnvironment, int aStackTop) { aEnvironment.iCurrentTokenizer = &aEnvironment.iXmlTokenizer; InternalTrue(aEnvironment, RESULT); } void LispExplodeTag(LispEnvironment& aEnvironment, int aStackTop) { LispPtr out(ARGUMENT(1)); CheckArgIsString(1, aEnvironment, aStackTop); const char* str = out->String()->c_str(); str++; if (str[0] != '<') { RESULT = (out); return; } str++; const char* type = (str[0] == '/') ? (str++, "\"Close\"") : "\"Open\""; std::string tag; tag.push_back('\"'); while (IsAlpha(*str)) { char c = *str++; if (c >= 'a' && c <= 'z') c = c + ('A' - 'a'); tag.push_back(c); } tag.push_back('\"'); LispObject* info = nullptr; while (*str == ' ') str++; while (*str != '>' && *str != '/') { std::string name; name.push_back('\"'); while (IsAlpha(*str)) { char c = *str++; if (c >= 'a' && c <= 'z') c = c + ('A' - 'a'); name.push_back(c); } name.push_back('\"'); CheckArg(str[0] == '=', 1, aEnvironment, aStackTop); str++; CheckArg(str[0] == '\"', 1, aEnvironment, aStackTop); std::string value; value.push_back(*str++); while (*str != '\"') value.push_back(*str++); value.push_back(*str++); info = LispSubList::New( LispObjectAdder(aEnvironment.iList->Copy()) + LispObjectAdder(LispAtom::New(aEnvironment, name)) + LispObjectAdder(LispAtom::New(aEnvironment, value))) + LispObjectAdder(info); while (*str == ' ') str++; } if (*str == '/') { type = "\"OpenClose\""; str++; while (*str == ' ') ++str; } info = LispSubList::New(LispObjectAdder(aEnvironment.iList->Copy()) + LispObjectAdder(info)); RESULT = (LispSubList::New( LispObjectAdder(LispAtom::New(aEnvironment, "XmlTag")) + LispObjectAdder(LispAtom::New(aEnvironment, tag)) + LispObjectAdder(info) + LispObjectAdder(LispAtom::New(aEnvironment, type)))); } void YacasBuiltinAssoc(LispEnvironment& aEnvironment, int aStackTop) { // Check that we have two arguments. // key to find LispPtr key(ARGUMENT(1)); // assoc-list to find it in LispPtr list(ARGUMENT(2)); LispObject* t; // Check that it is a compound object CheckArg(list->SubList(), 2, aEnvironment, aStackTop); t = (*list->SubList()); CheckArg(t, 2, aEnvironment, aStackTop); t = t->Nixed(); while (t) { if (t->SubList()) { LispObject* sub = (*t->SubList()); if (sub) { sub = sub->Nixed(); LispPtr temp(sub); if (InternalEquals(aEnvironment, key, temp)) { RESULT = (t); return; } } } t = t->Nixed(); } RESULT = (LispAtom::New(aEnvironment, "Empty")); } void LispCurrentFile(LispEnvironment& aEnvironment, int aStackTop) { RESULT = LispAtom::New(aEnvironment, stringify(aEnvironment.iInputStatus.FileName())); } void LispCurrentLine(LispEnvironment& aEnvironment, int aStackTop) { RESULT = LispAtom::New( aEnvironment, std::to_string(aEnvironment.iInputStatus.LineNumber())); } void LispBackQuote(LispEnvironment& aEnvironment, int aStackTop) { BackQuoteBehaviour behaviour(aEnvironment); LispPtr result; InternalSubstitute(result, ARGUMENT(1), behaviour); InternalEval(aEnvironment, RESULT, result); } void interpreter(LispEnvironment& aEnvironment, int aStackTop) { RESULT = (LispAtom::New(aEnvironment, "\"yacas\"")); } void LispVersion(LispEnvironment& aEnvironment, int aStackTop) { RESULT = (LispAtom::New(aEnvironment, "\"" YACAS_VERSION "\"")); } /// convert bits to digits. Use the kernel function bits_to_digits. Arguments /// must be small integers. void LispBitsToDigits(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; RefPtr y; GetNumber(x, aEnvironment, aStackTop, 1); GetNumber(y, aEnvironment, aStackTop, 2); long result = 0; // initialize just in case if (x->IsInt() && x->IsSmall() && y->IsInt() && y->IsSmall()) { // bits_to_digits uses unsigned long, see numbers.h unsigned base = unsigned(y->Double()); result = bits_to_digits((unsigned long)(x->Double()), base); } else { std::ostringstream buf; buf << "BitsToDigits: error: arguments (" << x->Double() << ", " << y->Double() << " must be small integers"; throw LispErrGeneric(buf.str()); } BigNumber* z = new BigNumber(std::to_string(result), aEnvironment.BinaryPrecision()); RESULT = (new LispNumber(z)); } /// convert digits to bits. Use the kernel function digits_to_bits. Arguments /// must be small integers. void LispDigitsToBits(LispEnvironment& aEnvironment, int aStackTop) { RefPtr x; RefPtr y; GetNumber(x, aEnvironment, aStackTop, 1); GetNumber(y, aEnvironment, aStackTop, 2); long result = 0; // initialize just in case if (x->IsInt() && x->IsSmall() && y->IsInt() && y->IsSmall()) { // bits_to_digits uses unsigned long, see numbers.h unsigned base = unsigned(y->Double()); result = digits_to_bits((unsigned long)(x->Double()), base); } else { std::ostringstream buf; buf << "BitsToDigits: error: arguments (" << x->Double() << ", " << y->Double() << " must be small integers"; throw LispErrGeneric(buf.str()); } BigNumber* z = new BigNumber(std::to_string(result), aEnvironment.BinaryPrecision()); RESULT = (new LispNumber(z)); } ================================================ FILE: cyacas/libyacas/src/mathuserfunc.cpp ================================================ #include "yacas/mathuserfunc.h" #include "yacas/lispeval.h" #include "yacas/lispobject.h" #include "yacas/patternclass.h" #include "yacas/patterns.h" #include "yacas/standard.h" #include "yacas/substitute.h" #include #define InternalEval aEnvironment.iEvaluator->Eval bool BranchingUserFunction::BranchRule::Matches(LispEnvironment& aEnvironment, LispPtr* aArguments) { LispPtr pred; InternalEval(aEnvironment, pred, iPredicate); return IsTrue(aEnvironment, pred); } int BranchingUserFunction::BranchRule::Precedence() const { return iPrecedence; } LispPtr& BranchingUserFunction::BranchRule::Body() { return iBody; } bool BranchingUserFunction::BranchRuleTruePredicate::Matches( LispEnvironment& aEnvironment, LispPtr* aArguments) { return true; } bool BranchingUserFunction::BranchPattern::Matches( LispEnvironment& aEnvironment, LispPtr* aArguments) { return iPatternClass->Matches(aEnvironment, aArguments); } int BranchingUserFunction::BranchPattern::Precedence() const { return iPrecedence; } LispPtr& BranchingUserFunction::BranchPattern::Body() { return iBody; } BranchingUserFunction::BranchingUserFunction(LispPtr& aParameters) : iParameters(), iRules(), iParamList(aParameters) { for (LispIterator iter(aParameters); iter.getObj(); ++iter) { if (!iter.getObj()->String()) throw LispErrCreatingUserFunction(); BranchParameter param(iter.getObj()->String()); iParameters.push_back(param); } } BranchingUserFunction::~BranchingUserFunction() { for (BranchRuleBase* p : iRules) delete p; } void BranchingUserFunction::Evaluate(LispPtr& aResult, LispEnvironment& aEnvironment, LispPtr& aArguments) const { const unsigned arity = Arity(); if (Traced()) { LispPtr tr(LispSubList::New(aArguments)); TraceShowEnter(aEnvironment, tr); tr = nullptr; } LispIterator iter(aArguments); ++iter; // unrollable arguments std::unique_ptr arguments(arity == 0 ? nullptr : new LispPtr[arity]); // Walk over all arguments, evaluating them as necessary for (unsigned i = 0; i < arity; ++i, ++iter) { if (!iter.getObj()) throw LispErrWrongNumberOfArgs(); if (iParameters[i].iHold) { arguments[i] = iter.getObj()->Copy(); } else { // Check(iter.getObj(), KLispErrWrongNumberOfArgs); // checked // above InternalEval(aEnvironment, arguments[i], *iter); } } if (Traced()) { LispIterator iter(aArguments); for (unsigned i = 0; i < arity; ++i) TraceShowArg(aEnvironment, *++iter, arguments[i]); } // declare a new local stack. LispLocalFrame frame(aEnvironment, Fenced()); // define the local variables. for (unsigned i = 0; i < arity; ++i) { const LispString* variable = iParameters[i].iParameter; // set the variable to the new value aEnvironment.NewLocal(variable, arguments[i]); } // walk the rules database, returning the evaluated result if the // predicate is true. const std::size_t nrRules = iRules.size(); UserStackInformation& st = aEnvironment.iEvaluator->StackInformation(); for (std::size_t i = 0; i < nrRules; i++) { BranchRuleBase* thisRule = iRules[i]; assert(thisRule); st.iRulePrecedence = thisRule->Precedence(); bool matches = thisRule->Matches(aEnvironment, arguments.get()); if (matches) { st.iSide = 1; InternalEval(aEnvironment, aResult, thisRule->Body()); goto FINISH; } // If rules got inserted, walk back while (thisRule != iRules[i] && i > 0) i--; } // No predicate was true: return a new expression with the evaluated // arguments. { LispPtr full(aArguments->Copy()); if (arity == 0) { full->Nixed() = nullptr; } else { full->Nixed() = arguments[0]; for (unsigned i = 0; i < arity - 1; ++i) arguments[i]->Nixed() = arguments[i + 1]; } aResult = LispSubList::New(full); } FINISH: if (Traced()) { LispPtr tr(LispSubList::New(aArguments)); TraceShowLeave(aEnvironment, aResult, tr); tr = nullptr; } } void BranchingUserFunction::HoldArgument(const LispString* aVariable) { const std::size_t nrc = iParameters.size(); for (std::size_t i = 0; i < nrc; ++i) { if (iParameters[i].iParameter == aVariable) iParameters[i].iHold = true; } } unsigned BranchingUserFunction::Arity() const { return iParameters.size(); } bool BranchingUserFunction::IsArity(unsigned aArity) const { return Arity() == aArity; } void BranchingUserFunction::DeclareRule(int aPrecedence, LispPtr& aPredicate, LispPtr& aBody) { // New branching rule. BranchRule* newRule = new BranchRule(aPrecedence, aPredicate, aBody); if (!newRule) throw LispErrCreatingRule(); InsertRule(aPrecedence, newRule); } void BranchingUserFunction::DeclareRule(int aPrecedence, LispPtr& aBody) { // New branching rule. BranchRule* newRule = new BranchRuleTruePredicate(aPrecedence, aBody); if (!newRule) throw LispErrCreatingRule(); InsertRule(aPrecedence, newRule); } void BranchingUserFunction::DeclarePattern(int aPrecedence, LispPtr& aPredicate, LispPtr& aBody) { // New branching rule. BranchPattern* newRule = new BranchPattern(aPrecedence, aPredicate, aBody); if (!newRule) throw LispErrCreatingRule(); InsertRule(aPrecedence, newRule); } void BranchingUserFunction::InsertRule(int aPrecedence, BranchRuleBase* newRule) { // Find place to insert int low, high, mid; low = 0; high = iRules.size(); // Constant time: find out if the precedence is before any of the // currently defined rules or past them. if (high > 0) { if (iRules[0]->Precedence() > aPrecedence) { mid = 0; goto CONTINUE; } if (iRules[high - 1]->Precedence() < aPrecedence) { mid = high; goto CONTINUE; } } // Otherwise, O(log n) search algorithm for place to insert for (;;) { if (low >= high) { mid = low; goto CONTINUE; } mid = (low + high) >> 1; if (iRules[mid]->Precedence() > aPrecedence) { high = mid; } else if (iRules[mid]->Precedence() < aPrecedence) { low = (++mid); } else { goto CONTINUE; } } CONTINUE: // Insert it iRules.insert(iRules.begin() + mid, newRule); } const LispPtr& BranchingUserFunction::ArgList() const { return iParamList; } ListedBranchingUserFunction::ListedBranchingUserFunction(LispPtr& aParameters) : BranchingUserFunction(aParameters) { } bool ListedBranchingUserFunction::IsArity(unsigned aArity) const { // nr arguments handled is bound by a minimum: the number of arguments // to this function. return Arity() <= aArity; } void ListedBranchingUserFunction::Evaluate(LispPtr& aResult, LispEnvironment& aEnvironment, LispPtr& aArguments) const { LispPtr newArgs; LispIterator iter(aArguments); LispPtr* ptr = &newArgs; const int arity = Arity(); // Make a copy of the arguments first // TODO: if we were to change the internal representation to a cons cell, // this copying would not be needed for (int i = 0; i < arity && iter.getObj(); ++i, ++iter) { *ptr = iter.getObj()->Copy(); ptr = &((*ptr)->Nixed()); } if (!iter.getObj()->Nixed()) { (*ptr) = (iter.getObj()->Copy()); ++iter; assert(!iter.getObj()); } else { LispPtr head(aEnvironment.iList->Copy()); head->Nixed() = iter.getObj(); *ptr = (LispSubList::New(head)); } BranchingUserFunction::Evaluate(aResult, aEnvironment, newArgs); } MacroUserFunction::MacroUserFunction(LispPtr& aParameters) : BranchingUserFunction(aParameters) { LispIterator iter(aParameters); for (int i = 0; iter.getObj(); i++, ++iter) { if (!iter.getObj()->String()) throw LispErrCreatingUserFunction(); iParameters[i].iHold = true; } UnFence(); } void MacroUserFunction::Evaluate(LispPtr& aResult, LispEnvironment& aEnvironment, LispPtr& aArguments) const { const unsigned arity = Arity(); if (Traced()) { LispPtr tr(LispSubList::New(aArguments)); TraceShowEnter(aEnvironment, tr); tr = (nullptr); } LispIterator iter(aArguments); ++iter; // unrollable arguments std::unique_ptr arguments(arity == 0 ? nullptr : new LispPtr[arity]); // Walk over all arguments, evaluating them as necessary for (unsigned i = 0; i < arity; ++i, ++iter) { if (!iter.getObj()) throw LispErrWrongNumberOfArgs(); if (iParameters[i].iHold) arguments[i] = iter.getObj()->Copy(); else InternalEval(aEnvironment, arguments[i], *iter); } if (Traced()) { LispIterator iter(aArguments); // TODO: ideally we would only need an iterator here ++iter; for (unsigned i = 0; i < arity; ++i) { TraceShowArg(aEnvironment, *iter, arguments[i]); ++iter; } } LispPtr substedBody; { // declare a new local stack. LispLocalFrame frame(aEnvironment, false); // define the local variables. for (unsigned i = 0; i < arity; ++i) { const LispString* variable = iParameters[i].iParameter; // set the variable to the new value aEnvironment.NewLocal(variable, arguments[i]); } // walk the rules database, returning the evaluated result if the // predicate is true. const std::size_t nrRules = iRules.size(); UserStackInformation& st = aEnvironment.iEvaluator->StackInformation(); for (std::size_t i = 0; i < nrRules; i++) { BranchRuleBase* thisRule = iRules[i]; assert(thisRule); st.iRulePrecedence = thisRule->Precedence(); const bool matches = thisRule->Matches(aEnvironment, arguments.get()); if (matches) { st.iSide = 1; BackQuoteBehaviour behaviour(aEnvironment); InternalSubstitute(substedBody, thisRule->Body(), behaviour); break; } // If rules got inserted, walk back while (thisRule != iRules[i] && i > 0) i--; } } if (!!substedBody) { InternalEval(aEnvironment, aResult, substedBody); } else // No predicate was true: return a new expression with the evaluated // arguments. { LispPtr full(aArguments->Copy()); if (arity == 0) { full->Nixed() = nullptr; } else { full->Nixed() = arguments[0]; for (unsigned i = 0; i + 1 < arity; ++i) { arguments[i]->Nixed() = arguments[i + 1]; } } aResult = LispSubList::New(full); } if (Traced()) { LispPtr tr(LispSubList::New(aArguments)); TraceShowLeave(aEnvironment, aResult, tr); tr = nullptr; } } ListedMacroUserFunction::ListedMacroUserFunction(LispPtr& aParameters) : MacroUserFunction(aParameters) { } bool ListedMacroUserFunction::IsArity(unsigned aArity) const { return Arity() <= aArity; } void ListedMacroUserFunction::Evaluate(LispPtr& aResult, LispEnvironment& aEnvironment, LispPtr& aArguments) const { LispPtr newArgs; LispIterator iter(aArguments); LispPtr* ptr = &newArgs; const int arity = Arity(); // TODO: the code would look a lot easier if we could do with only an // iterator for (int i = 0; i < arity && iter.getObj(); ++i, ++iter) { *ptr = (*iter)->Copy(); ptr = &((*ptr)->Nixed()); } if (!iter.getObj()->Nixed()) { *ptr = iter.getObj()->Copy(); (*ptr)->Nixed(); ++iter; assert(!iter.getObj()); } else { LispPtr head(aEnvironment.iList->Copy()); head->Nixed() = iter.getObj(); *ptr = LispSubList::New(head); } MacroUserFunction::Evaluate(aResult, aEnvironment, newArgs); } ================================================ FILE: cyacas/libyacas/src/mempool.cpp ================================================ #include "yacas/mempool.h" #include #include MemPool::MemPool(unsigned block_size, unsigned no_blocks) : _block_size(std::max(static_cast(block_size), sizeof(void*))), _no_blocks(no_blocks), _no_free_blocks(no_blocks), _no_initialized_blocks(0), _pool(new std::uint8_t[_block_size * _no_blocks]), _next_free_block(_pool), _next_pool(nullptr) { } MemPool::~MemPool() noexcept { assert(_no_free_blocks == _no_blocks); delete _next_pool; delete[] _pool; } void* MemPool::alloc() { if (_no_free_blocks) { if (_no_initialized_blocks <= _no_blocks - _no_free_blocks) { std::uint8_t* p = _pool + _no_initialized_blocks * _block_size; *reinterpret_cast(p) = p + _block_size; _no_initialized_blocks += 1; } void* ret = _next_free_block; if (--_no_free_blocks) _next_free_block = *reinterpret_cast(_next_free_block); else _next_free_block = nullptr; return ret; } if (!_next_pool) _next_pool = new MemPool(_block_size, _no_blocks); return _next_pool->alloc(); } void MemPool::free(void* p) noexcept { if (p >= _pool && p < _pool + _block_size * _no_blocks) { if (_next_free_block) { *reinterpret_cast(p) = _next_free_block; _next_free_block = static_cast(p); } else { *reinterpret_cast(p) = _pool + _no_blocks; _next_free_block = static_cast(p); } _no_free_blocks += 1; } else { _next_pool->free(p); } } ================================================ FILE: cyacas/libyacas/src/numbers.cpp ================================================ #include "yacas/numbers.h" #include "yacas/errors.h" #include "yacas/standard.h" #include #include ////////////////////////////////////////////////// ///// bits_to_digits and digits_to_bits implementation ////////////////////////////////////////////////// // lookup table for transforming the number of digits static const unsigned log2_table_size = 32; // report the table size unsigned log2_table_range() { return log2_table_size; } // A lookup table of Ln(n)/Ln(2) for n = 1 .. 32. // Generated by: PrintList(N(Ln(1 .. 32)/Ln(2)), ",") at precision 40 const double log2_table[log2_table_size] = { 0., 1., 1.5849625007211561814537389439478165087598, 2., 2.3219280948873623478703194294893901758648, 2.5849625007211561814537389439478165087598, 2.807354922057604107441969317231830808641, 3., 3.1699250014423123629074778878956330175196, 3.3219280948873623478703194294893901758648, 3.4594316186372972561993630467257929587032, 3.5849625007211561814537389439478165087598, 3.7004397181410921603968126542566947336284, 3.807354922057604107441969317231830808641, 3.9068905956085185293240583734372066846246, 4., 4.0874628412503394082540660108104043540112, 4.1699250014423123629074778878956330175196, 4.2479275134435854937935194229068344226935, 4.3219280948873623478703194294893901758648, 4.3923174227787602888957082611796473174008, 4.4594316186372972561993630467257929587032, 4.5235619560570128722941482441626688444988, 4.5849625007211561814537389439478165087598, 4.6438561897747246957406388589787803517296, 4.7004397181410921603968126542566947336284, 4.7548875021634685443612168318434495262794, 4.807354922057604107441969317231830808641, 4.8579809951275721207197733246279847624768, 4.9068905956085185293240583734372066846246, 4.9541963103868752088061235991755544235489, 5.}; // table look-up of small integer logarithms, for converting the number of // digits to binary and back double log2_table_lookup(unsigned n) { if (n <= log2_table_size && n >= BASE2) return log2_table[n - 1]; std::ostringstream buf; buf << "log2_table_lookup: error: invalid argument " << n; throw LispErrGeneric(buf.str()); } // convert the number of digits in given base to the number of bits, and back. // need to round the number of digits. // to make sure that there is no hysteresis, we round upwards on digits_to_bits // but round down on bits_to_digits unsigned long digits_to_bits(unsigned long digits, unsigned base) { return static_cast( std::ceil(double(digits) * log2_table_lookup(base))); } unsigned long bits_to_digits(unsigned long bits, unsigned base) { return static_cast( std::floor(double(bits) / log2_table_lookup(base))); } ////////////////////////////////////////////////// ///// End of bits_to_digits and digits_to_bits implementation ////////////////////////////////////////////////// ================================================ FILE: cyacas/libyacas/src/patcher.cpp ================================================ #include "yacas/patcher.h" #include "yacas/lisperror.h" #include "yacas/lispio.h" #include "yacas/standard.h" #include /** PatchLoad: patch a string, and write to current output. * Everything between is evaluated. The result * is thrown away. */ void PatchLoad(const std::string& content, std::ostream& out, LispEnvironment& env) { std::size_t i = 0; for (;;) { const std::size_t p = content.find("", p + 2); if (q == std::string::npos) throw LispErrGeneric("closing tag not found when patching"); InputStatus oldstatus = env.iInputStatus; env.iInputStatus.SetTo("String"); StringInput newInput(content.substr(p + 2, q - p - 2), env.iInputStatus); LispLocalInput localInput(env, &newInput); DoInternalLoad(env, &newInput); env.iInputStatus.RestoreFrom(oldstatus); i = q + 2; } } ================================================ FILE: cyacas/libyacas/src/patternclass.cpp ================================================ #include "yacas/patternclass.h" PatternClass::PatternClass(YacasPatternPredicateBase* aPatternMatcher) : iPatternMatcher(aPatternMatcher) { } PatternClass::~PatternClass() { delete iPatternMatcher; } const char* PatternClass::TypeName() const { return "\"Pattern\""; } bool PatternClass::Matches(LispEnvironment& aEnvironment, LispPtr& aArguments) { assert(iPatternMatcher); return iPatternMatcher->Matches(aEnvironment, aArguments); } bool PatternClass::Matches(LispEnvironment& aEnvironment, LispPtr* aArguments) { assert(iPatternMatcher); return iPatternMatcher->Matches(aEnvironment, aArguments); } ================================================ FILE: cyacas/libyacas/src/patterns.cpp ================================================ #include "yacas/patterns.h" #include "yacas/lispeval.h" #include "yacas/lispobject.h" #include "yacas/mathuserfunc.h" #include "yacas/standard.h" #include bool MatchAtom::ArgumentMatches(LispEnvironment& aEnvironment, LispPtr& aExpression, LispPtr* arguments) const { // If it is a floating point, don't even bother comparing if (!!aExpression) if (aExpression->Number(0)) if (!aExpression->Number(0)->IsInt()) return false; return (iString == aExpression->String()); } bool MatchNumber::ArgumentMatches(LispEnvironment& aEnvironment, LispPtr& aExpression, LispPtr* arguments) const { if (aExpression->Number(aEnvironment.Precision())) return iNumber->Equals(*aExpression->Number(aEnvironment.Precision())); return false; } bool MatchVariable::ArgumentMatches(LispEnvironment& aEnvironment, LispPtr& aExpression, LispPtr* arguments) const { if (!arguments[iVarIndex]) { arguments[iVarIndex] = aExpression; return true; } if (InternalEquals(aEnvironment, aExpression, arguments[iVarIndex])) return true; return false; } bool MatchSubList::ArgumentMatches(LispEnvironment& aEnvironment, LispPtr& aExpression, LispPtr* arguments) const { if (!aExpression->SubList()) return false; LispIterator iter(aExpression); LispObject* pObj = iter.getObj(); if (!pObj) throw LispErrInvalidArg(); LispPtr* pPtr = pObj->SubList(); if (!pPtr) throw LispErrNotList(); iter = *pPtr; const int iNrMatchers = iMatchers.size(); for (int i = 0; i < iNrMatchers; i++, ++iter) { if (!iter.getObj()) return false; if (!iMatchers[i]->ArgumentMatches(aEnvironment, *iter, arguments)) return false; } if (iter.getObj()) return false; return true; } int YacasPatternPredicateBase::LookUp(const LispString* aVariable) { const std::size_t n = iVariables.size(); for (std::size_t i = 0; i < n; ++i) if (iVariables[i] == aVariable) return i; iVariables.push_back(aVariable); return iVariables.size() - 1; } const YacasParamMatcherBase* YacasPatternPredicateBase::MakeParamMatcher(LispEnvironment& aEnvironment, LispObject* aPattern) { if (!aPattern) return nullptr; if (aPattern->Number(aEnvironment.Precision())) return new MatchNumber(aPattern->Number(aEnvironment.Precision())); // Deal with atoms if (aPattern->String()) return new MatchAtom(aPattern->String()); // Else it must be a sublist if (aPattern->SubList()) { // See if it is a variable template: LispPtr* sublist = aPattern->SubList(); assert(sublist); int num = InternalListLength(*sublist); // variable matcher here... if (num > 1) { LispObject* head = (*sublist); if (head->String() == aEnvironment.HashTable().LookUp("_")) { LispObject* second = head->Nixed(); if (second->String()) { int index = LookUp(second->String()); // Make a predicate for the type, if needed if (num > 2) { LispPtr third; LispObject* predicate = second->Nixed(); if (predicate->SubList()) { InternalFlatCopy(third, *predicate->SubList()); } else { third = (second->Nixed()->Copy()); } LispObject* last = third; while (!!last->Nixed()) last = last->Nixed(); last->Nixed() = LispAtom::New(aEnvironment, *second->String()); iPredicates.push_back(LispPtr(LispSubList::New(third))); } return new MatchVariable(index); } } } std::vector matchers; matchers.reserve(num); LispIterator iter(*sublist); for (int i = 0; i < num; ++i, ++iter) { matchers.push_back(MakeParamMatcher(aEnvironment, iter.getObj())); assert(matchers[i]); } return new MatchSubList(std::move(matchers)); } return nullptr; } YacasPatternPredicateBase::YacasPatternPredicateBase( LispEnvironment& aEnvironment, LispPtr& aPattern, LispPtr& aPostPredicate) { for (LispIterator iter(aPattern); iter.getObj(); ++iter) { const YacasParamMatcherBase* matcher = MakeParamMatcher(aEnvironment, iter.getObj()); assert(matcher != nullptr); iParamMatchers.push_back(matcher); } iPredicates.push_back(aPostPredicate); } bool YacasPatternPredicateBase::Matches(LispEnvironment& aEnvironment, LispPtr& aArguments) { std::unique_ptr arguments( iVariables.empty() ? nullptr : new LispPtr[iVariables.size()]); LispIterator iter(aArguments); const std::size_t n = iParamMatchers.size(); for (std::size_t i = 0; i < n; ++i, ++iter) { if (!iter.getObj()) return false; if (!iParamMatchers[i]->ArgumentMatches( aEnvironment, *iter, arguments.get())) return false; } if (iter.getObj()) return false; { // set the local variables. LispLocalFrame frame(aEnvironment, false); SetPatternVariables(aEnvironment, arguments.get()); // do the predicates if (!CheckPredicates(aEnvironment)) return false; } // set the local variables for sure now SetPatternVariables(aEnvironment, arguments.get()); return true; } bool YacasPatternPredicateBase::Matches(LispEnvironment& aEnvironment, LispPtr* aArguments) { std::unique_ptr arguments( iVariables.empty() ? nullptr : new LispPtr[iVariables.size()]); const std::size_t n = iParamMatchers.size(); for (std::size_t i = 0; i < n; ++i) if (!iParamMatchers[i]->ArgumentMatches( aEnvironment, aArguments[i], arguments.get())) return false; { // set the local variables. LispLocalFrame frame(aEnvironment, false); SetPatternVariables(aEnvironment, arguments.get()); // do the predicates if (!CheckPredicates(aEnvironment)) return false; } // set the local variables for sure now SetPatternVariables(aEnvironment, arguments.get()); return true; } bool YacasPatternPredicateBase::CheckPredicates(LispEnvironment& aEnvironment) { const std::size_t n = iPredicates.size(); for (std::size_t i = 0; i < n; ++i) { LispPtr pred; aEnvironment.iEvaluator->Eval(aEnvironment, pred, iPredicates[i]); if (IsFalse(aEnvironment, pred)) { return false; } // If the result is not False, it should be True, else probably // something is wrong (the expression returned unevaluated) bool isTrue = IsTrue(aEnvironment, pred); if (!isTrue) { #define LIM_AL 60 LispString strout; aEnvironment.iErrorOutput << "The predicate\n\t"; PrintExpression(strout, iPredicates[i], aEnvironment, LIM_AL); aEnvironment.iErrorOutput << strout; aEnvironment.iErrorOutput << "\nevaluated to\n\t"; PrintExpression(strout, pred, aEnvironment, LIM_AL); aEnvironment.iErrorOutput << strout << '\n'; ShowStack(aEnvironment); throw LispErrMaxRecurseDepthReached(); } } return true; } void YacasPatternPredicateBase::SetPatternVariables( LispEnvironment& aEnvironment, LispPtr* arguments) { const std::size_t n = iVariables.size(); for (std::size_t i = 0; i < n; ++i) aEnvironment.NewLocal(iVariables[i], arguments[i]); } YacasPatternPredicateBase::~YacasPatternPredicateBase() { for (const YacasParamMatcherBase* p : iParamMatchers) delete p; } ================================================ FILE: cyacas/libyacas/src/platmath.cpp ================================================ /* Math using the standard library, if the precision is less than 13 */ #include "yacas/platmath.h" #include "yacas/errors.h" #include "yacas/lispatom.h" #include "yacas/lispenvironment.h" #include "yacas/lispobject.h" #include "yacas/numbers.h" #include #include #include double GetDouble(LispObject* aInteger) { BigNumber* number = aInteger->Number(0); if (!number) { std::ostringstream buf; buf << "Argument is not a number: " << aInteger->String(); throw LispErrGeneric(buf.str()); } return number->Double(); } LispObject* Double(LispEnvironment& aEnvironment, double aValue) { std::ostringstream buf; buf << aValue; return LispAtom::New(aEnvironment, buf.str()); } // LispObject* // PlatArcSin(LispEnvironment& aEnvironment, LispObject* int1, int aPrecision) // { // return Double(aEnvironment, std::asin(GetDouble(int1))); // } // LispObject* // PlatLn(LispEnvironment& aEnvironment, LispObject* int1, int aPrecision) // { // return Double(aEnvironment, std::log(GetDouble(int1))); // } // LispObject* PlatPower(LispEnvironment& aEnvironment, // LispObject* int1, // LispObject* int2, // int aPrecision) // { // return Double(aEnvironment, std::pow(GetDouble(int1), GetDouble(int2))); // } // LispObject* PlatDiv(LispEnvironment& aEnvironment, // LispObject* int1, // LispObject* int2, // int aPrecision) // { // return Double(aEnvironment, // ((long)GetDouble(int1)) / ((long)GetDouble(int2))); // } namespace { static const std::size_t MAX_SMALL_PRIME = 65537; static std::bitset _primes_table; static class InitPrimesTable { public: InitPrimesTable(); } _init_primes_table; InitPrimesTable::InitPrimesTable() { for (std::size_t i = 3; i < MAX_SMALL_PRIME; i += 2) { if (_primes_table.test(i / 2)) continue; for (std::size_t j = 3; j < MAX_SMALL_PRIME / i; j += 2) _primes_table.set((i * j) / 2); } } } unsigned primes_table_check(unsigned long p) { if (p == 0) return MAX_SMALL_PRIME; if (p == 2) return 1; if (p < 2 || p > MAX_SMALL_PRIME || (p & 1) == 0) return 0; return !_primes_table.test(p / 2); } LispObject* PlatIsPrime(LispEnvironment& aEnvironment, LispObject* int1, int aPrecision) { return Double(aEnvironment, primes_table_check((unsigned long)(GetDouble(int1)))); } ================================================ FILE: cyacas/libyacas/src/standard.cpp ================================================ // \file standard.cpp // Implementation of some standard lisp operations // #include "yacas/standard.h" #include "yacas/lispatom.h" #include "yacas/lispenvironment.h" #include "yacas/lisperror.h" #include "yacas/infixparser.h" #include "yacas/lispenvironment.h" #include "yacas/lispeval.h" #include "yacas/lispio.h" #include "yacas/numbers.h" #include "yacas/platfileio.h" #include "yacas/stringio.h" #include "yacas/tokenizer.h" #include bool InternalIsList(const LispEnvironment& env, const LispPtr& aPtr) { if (!aPtr) return false; if (!aPtr->SubList()) return false; if (!(*aPtr->SubList())) return false; if ((*aPtr->SubList())->String() != env.iList->String()) return false; return true; } bool InternalIsString(const LispString* aOriginal) { return aOriginal && aOriginal->length() > 1 && aOriginal->front() == '\"' && aOriginal->back() == '\"'; } /* TODO: in documenting the choices made in the C++ engine, perhaps document why I pass objects that should contain the result by reference. Result string passed in by reference to avoid copy-constructors etcetera (allowing the code to share the same LispString in different places). */ std::string InternalUnstringify(const std::string& s) { /*TODO: should these not be checked also higher up, and should this not be * an assert at this level? ideally this function should be as efficient as * possible (allowing for a code generator to generate compiled code that * calls this function immediately. The compiler could prove that the input * is valid, so the checks would not be needed here in a non-debug run). * * Also do not forget to make the change in the Java version then, and find * the other places where this is relevant. */ if (s.size() < 2 || s.front() != '\"' || s.back() != '\"') throw LispErrInvalidArg(); return std::string(s.c_str() + 1, s.size() - 2); } int InternalAsciiToInt(const LispString& aString) { const char* ptr = aString.c_str(); if (!IsNumber(ptr, false)) throw LispErrInvalidArg(); return std::stoi(aString); } bool IsNumber(const std::string& s, bool aAllowFloat) { const char* ptr = s.c_str(); if (*ptr == '-' || *ptr == '+') ptr++; int nrDigits = 0; int index = 0; while (std::isdigit(ptr[index])) { nrDigits++; index++; } if (ptr[index] == '.') { if (!aAllowFloat) return false; index++; while (std::isdigit(ptr[index])) { nrDigits++; index++; } } if (nrDigits == 0) return false; if (ptr[index] == 'e' || ptr[index] == 'E') { if (!aAllowFloat) return false; index++; if (ptr[index] == '-' || ptr[index] == '+') index++; while (ptr[index] >= '0' && ptr[index] <= '9') index++; } if (ptr[index] != '\0') return false; return true; } void InternalNth(LispPtr& aResult, const LispPtr& aArg, int n) { if (n < 0 || !aArg || !aArg->SubList()) throw LispErrInvalidArg(); LispIterator iter(*aArg->SubList()); while (n > 0) { if (!iter.getObj()) throw LispErrInvalidArg(); ++iter; n--; } if (!iter.getObj()) throw LispErrInvalidArg(); aResult = (iter.getObj()->Copy()); } void InternalTail(LispPtr& aResult, const LispPtr& aArg) { if (!aArg) throw LispErrInvalidArg(); LispPtr* iter = aArg->SubList(); if (!iter || !*iter) throw LispErrInvalidArg(); aResult = (LispSubList::New((*iter)->Nixed())); } void InternalReverseList(LispPtr& aResult, const LispPtr& aOriginal) { LispPtr iter(aOriginal); LispPtr previous; LispPtr tail(aOriginal); while (!!iter) { tail = iter->Nixed(); iter->Nixed() = (previous); previous = iter; iter = tail; } aResult = previous; } void InternalFlatCopy(LispPtr& aResult, const LispPtr& aOriginal) { LispConstIterator orig(aOriginal); LispIterator res(aResult); while (orig.getObj()) { (*res) = (orig.getObj()->Copy()); ++orig; ++res; } } std::size_t InternalListLength(const LispPtr& aOriginal) { LispConstIterator iter(aOriginal); std::size_t length = 0; while (iter.getObj()) { ++iter; length++; } return length; } bool InternalStrictTotalOrder(const LispEnvironment& env, const LispPtr& e1, const LispPtr& e2) { if (e1.ptr() == e2.ptr()) return false; if (!e1.ptr() && e2.ptr()) return true; if (e1.ptr() && !e2.ptr()) return false; const BigNumber* n1 = e1->Number(env.Precision()); const BigNumber* n2 = e2->Number(env.Precision()); if (n1 && !n2) return true; if (!n1 && n2) return false; if (n1 && n2) { if (n1->LessThan(*n2)) return true; if (!n1->Equals(*n2)) return false; return InternalStrictTotalOrder(env, e1->Nixed(), e2->Nixed()); } const LispString* s1 = e1->String(); const LispString* s2 = e2->String(); if (s1 && !s2) return true; if (!s1 && s2) return false; if (s1 && s2) { const int c = s1->compare(*s2); if (c) return c < 0; return InternalStrictTotalOrder(env, e1->Nixed(), e2->Nixed()); } LispPtr* l1 = e1->SubList(); LispPtr* l2 = e2->SubList(); if (!l1 && l2) return true; if (l1 && !l2) return false; if (l1 && l2) { LispIterator i1(*l1); LispIterator i2(*l2); while (i1.getObj() && i2.getObj()) { const LispPtr& p1 = *i1; const LispPtr& p2 = *i2; if (InternalEquals(env, p1, p2)) { ++i1; ++i2; continue; } return InternalStrictTotalOrder(env, p1, p2); } if (i1.getObj()) return false; if (i2.getObj()) return true; return false; } // FIXME: deal with generics // GenericClass* g1 = e1->Generic(); // GenericClass* g2 = e2->Generic(); // return false; } bool InternalEquals(const LispEnvironment& aEnvironment, const LispPtr& aExpression1, const LispPtr& aExpression2) { // Handle pointers to same, or nullptr if (aExpression1.ptr() == aExpression2.ptr()) // compare pointers to LispObject return true; if (!aExpression1.ptr() || !aExpression2.ptr()) return false; /*TODO This code would be better, if BigNumber::Equals works*/ BigNumber* n1 = aExpression1->Number(aEnvironment.Precision()); BigNumber* n2 = aExpression2->Number(aEnvironment.Precision()); if (!(!n1 && !n2)) { if (n1 == n2) { return true; } if (!n1) return false; if (!n2) return false; if (n1->Equals(*n2)) return true; // this should be enabled return false; } // Pointers to strings should be the same if (aExpression1->String() != aExpression2->String()) { return false; } // Handle same sublists, or nullptr if (aExpression1->SubList() == aExpression2->SubList()) { return true; } // Now check the sublists if (aExpression1->SubList()) { if (!aExpression2->SubList()) { return false; } LispIterator iter1(*aExpression1->SubList()); LispIterator iter2(*aExpression2->SubList()); while (iter1.getObj() && iter2.getObj()) { // compare two list elements if (!InternalEquals(aEnvironment, *iter1, *iter2)) { return false; } // Step to next ++iter1; ++iter2; } // Lists don't have the same length if (iter1.getObj() != iter2.getObj()) return false; // Same! return true; } // expressions sublists are not the same! return false; } void DoInternalLoad(LispEnvironment& aEnvironment, LispInput* aInput) { LispLocalInput localInput(aEnvironment, aInput); // TODO make "EndOfFile" a global thing // read-parse-eval to the end of file const LispString* eof = aEnvironment.HashTable().LookUp("EndOfFile"); bool endoffile = false; LispTokenizer tok; InfixParser parser(tok, *aEnvironment.CurrentInput(), aEnvironment, aEnvironment.PreFix(), aEnvironment.InFix(), aEnvironment.PostFix(), aEnvironment.Bodied()); while (!endoffile) { LispPtr readIn; // Read expression parser.Parse(readIn); if (!readIn) throw LispErrReadingFile(); // Check for end of file if (readIn->String() == eof) { endoffile = true; } // Else evaluate else { LispPtr result; aEnvironment.iEvaluator->Eval(aEnvironment, result, readIn); } } } void InternalLoad(LispEnvironment& aEnvironment, const std::string& aFileName) { const std::string oper = InternalUnstringify(aFileName); InputStatus oldstatus = aEnvironment.iInputStatus; aEnvironment.iInputStatus.SetTo(oper); // TODO make the file api platform independent!!!! // Open file LispLocalFile localFP( aEnvironment, oper, true, aEnvironment.iInputDirectories); if (!localFP.stream.is_open()) throw LispErrFileNotFound(); StdFileInput newInput(localFP, aEnvironment.iInputStatus); DoInternalLoad(aEnvironment, &newInput); aEnvironment.iInputStatus.RestoreFrom(oldstatus); } void InternalUse(LispEnvironment& aEnvironment, const std::string& aFileName) { LispDefFile* def = aEnvironment.DefFiles().File(aFileName); if (!def->IsLoaded()) { def->SetLoaded(); for (const LispString* s : def->symbols) aEnvironment.UnProtect(s); InternalLoad(aEnvironment, aFileName); for (const LispString* s : def->symbols) aEnvironment.Protect(s); } } void InternalApplyString(LispEnvironment& aEnvironment, LispPtr& aResult, const LispString* aOperator, LispPtr& aArgs) { if (!InternalIsString(aOperator)) throw LispErrNotString(); LispObject* head = LispAtom::New(aEnvironment, *SymbolName(aEnvironment, *aOperator)); head->Nixed() = (aArgs); LispPtr body(LispSubList::New(head)); aEnvironment.iEvaluator->Eval(aEnvironment, aResult, body); } void InternalApplyPure(LispPtr& oper, LispPtr& args2, LispPtr& aResult, LispEnvironment& aEnvironment) { LispPtr* chk1 = oper->SubList(); if (!chk1) throw LispErrInvalidArg(); LispPtr oper2((*chk1)->Nixed()); if (!oper2) throw LispErrInvalidArg(); LispPtr body(oper2->Nixed()); if (!body) throw LispErrInvalidArg(); LispPtr* chk2 = oper2->SubList(); if (!chk2 || !*chk2) throw LispErrInvalidArg(); oper2 = ((*chk2)->Nixed()); LispLocalFrame frame(aEnvironment, false); while (!!oper2) { if (!args2) throw LispErrInvalidArg(); const LispString* var = oper2->String(); if (!var) throw LispErrInvalidArg(); LispPtr newly(args2->Copy()); aEnvironment.NewLocal(var, newly); oper2 = (oper2->Nixed()); args2 = (args2->Nixed()); } if (args2) throw LispErrInvalidArg(); aEnvironment.iEvaluator->Eval(aEnvironment, aResult, body); } void InternalEvalString(LispEnvironment& aEnvironment, LispPtr& aResult, const char* aString) { LispString full(aString); full.push_back(';'); StringInput input(full, aEnvironment.iInputStatus); LispPtr lispexpr; LispTokenizer& tok = *aEnvironment.iCurrentTokenizer; InfixParser parser(tok, input, aEnvironment, aEnvironment.PreFix(), aEnvironment.InFix(), aEnvironment.PostFix(), aEnvironment.Bodied()); parser.Parse(lispexpr); aEnvironment.iEvaluator->Eval(aEnvironment, aResult, lispexpr); } LispObject* operator+(const LispObjectAdder& left, const LispObjectAdder& right) { LispObject* trav = left.iPtr; while (!!trav->Nixed()) { trav = trav->Nixed(); } trav->Nixed() = (right.iPtr); return left.iPtr; } void ParseExpression(LispPtr& aResult, const char* aString, LispEnvironment& aEnvironment) { LispString full(aString); full.push_back(';'); StringInput input(full, aEnvironment.iInputStatus); aEnvironment.iInputStatus.SetTo("String"); LispTokenizer& tok = *aEnvironment.iCurrentTokenizer; InfixParser parser(tok, input, aEnvironment, aEnvironment.PreFix(), aEnvironment.InFix(), aEnvironment.PostFix(), aEnvironment.Bodied()); parser.Parse(aResult); } void ReturnUnEvaluated(LispPtr& aResult, LispPtr& aArguments, LispEnvironment& aEnvironment) { LispPtr full(aArguments->Copy()); aResult = (LispSubList::New(full)); LispIterator iter(aArguments); ++iter; while (iter.getObj()) { LispPtr next; aEnvironment.iEvaluator->Eval(aEnvironment, next, *iter); full->Nixed() = (next); full = (next); ++iter; } full->Nixed() = (nullptr); } void PrintExpression(LispString& aResult, LispPtr& aExpression, LispEnvironment& aEnvironment, std::size_t aMaxChars) { std::ostringstream stream; InfixPrinter infixprinter(aEnvironment.PreFix(), aEnvironment.InFix(), aEnvironment.PostFix(), aEnvironment.Bodied()); infixprinter.Print(aExpression, stream, aEnvironment); aResult.assign(stream.str()); if (aMaxChars > 0 && aResult.size() > aMaxChars) { aResult.resize(aMaxChars - 3); aResult += "..."; } } const LispString* SymbolName(LispEnvironment& aEnvironment, const std::string& aSymbol) { if (aSymbol[0] == '\"') return aEnvironment.HashTable().LookUp( aSymbol.substr(1, aSymbol.size() - 2)); else return aEnvironment.HashTable().LookUp(aSymbol); } ================================================ FILE: cyacas/libyacas/src/stdfileio.cpp ================================================ #include "yacas/platfileio.h" #include #ifdef _WIN32 # define MAP_TO_WIN32_PATH_SEPARATOR #endif // WIN32 static void MapPathSeparators(std::string& filename) { #ifdef MAP_TO_WIN32_PATH_SEPARATOR for (std::size_t i = 0; i < filename.size(); ++i) if (filename[i] == '/') filename[i] = '\\'; #endif } StdFileInput::StdFileInput(std::istream& stream, InputStatus& aStatus) : LispInput(aStatus), _stream(stream) { } StdFileInput::StdFileInput(LispLocalFile& file, InputStatus& aStatus) : LispInput(aStatus), _stream(file.stream), _position(0), _cp_ready(false) { } char32_t StdFileInput::Next() { if (!_cp_ready) _get(); if (EndOfStream()) return std::char_traits::eof(); _cp_ready = false; _position += 1; return _cp; } char32_t StdFileInput::Peek() { if (EndOfStream()) return std::char_traits::eof(); if (!_cp_ready) _get(); return _cp; } void StdFileInput::Rewind() { _stream.seekg(0); _position = 0; _cp_ready = false; } bool StdFileInput::EndOfStream() const { if (_stream.eof()) return true; if (!_cp_ready) _get(); return _stream.eof(); } std::size_t StdFileInput::Position() const { return _position; } void StdFileInput::SetPosition(std::size_t n) { Rewind(); for (std::size_t i = 0; i < n; ++i) Next(); } void StdFileInput::_get() const { char p[4]; char* q = p; *q++ = _stream.get(); while (!_stream.eof() && !utf8::is_valid(p, q)) *q++ = _stream.get(); if (_stream.eof()) return; utf8::utf8to32(p, q, &_cp); if (_cp == '\n') iStatus.NextLine(); _cp_ready = true; } std::string InternalFindFile(const std::string& fname, const std::vector& dirs) { std::string path(fname); MapPathSeparators(path); std::unique_ptr f(new std::ifstream(path)); for (std::size_t i = 0; !f->good() && i < dirs.size(); ++i) { path = dirs[i] + fname; MapPathSeparators(path); f.reset(new std::ifstream(path)); } if (!f->good()) return ""; return path; } LispLocalFile::LispLocalFile(LispEnvironment& environment, const std::string& fname, bool read, const std::vector& dirs) : environment(environment) { std::string othername; if (read) { othername = fname; MapPathSeparators(othername); stream.open(othername, std::ios_base::in | std::ios_base::binary); for (std::size_t i = 0; !stream.is_open() && i < dirs.size(); ++i) { othername = dirs[i]; othername += fname; MapPathSeparators(othername); stream.open(othername, std::ios_base::in | std::ios_base::binary); } } else { othername = fname; MapPathSeparators(othername); stream.open(othername, std::ios_base::out); } } LispLocalFile::~LispLocalFile() { if (stream.is_open()) stream.close(); } ================================================ FILE: cyacas/libyacas/src/stringio.cpp ================================================ #include "yacas/stringio.h" StringInput::StringInput(const std::string& aString, InputStatus& aStatus) : LispInput(aStatus), _string(aString), _current(_string.begin()) { } char32_t StringInput::Next() { if (EndOfStream()) return std::char_traits::eof(); const char32_t cp = utf8::next(_current, std::string::const_iterator(_string.end())); if (cp == '\n') iStatus.NextLine(); return cp; } char32_t StringInput::Peek() { if (EndOfStream()) return std::char_traits::eof(); return utf8::peek_next(_current, std::string::const_iterator(_string.end())); } bool StringInput::EndOfStream() const { return _current == _string.end(); } std::size_t StringInput::Position() const { return utf8::distance(_string.begin(), _current); } void StringInput::SetPosition(std::size_t n) { _current = _string.begin(); utf8::advance(_current, n, std::string::const_iterator(_string.end())); } ================================================ FILE: cyacas/libyacas/src/substitute.cpp ================================================ #include "yacas/substitute.h" #include "yacas/lispatom.h" #include "yacas/lispeval.h" #include "yacas/standard.h" // Subst, Substitute, FullSubstitute void InternalSubstitute(LispPtr& aTarget, LispPtr& aSource, SubstBehaviourBase& aBehaviour) { LispObject* object = aSource; assert(object); if (!aBehaviour.Matches(aTarget, aSource)) { LispPtr* oldList = object->SubList(); if (oldList) { LispPtr newList; LispPtr* next = &newList; while (!!(*oldList)) { InternalSubstitute(*next, *oldList, aBehaviour); oldList = &(*oldList)->Nixed(); next = &(*next)->Nixed(); } aTarget = (LispSubList::New(newList)); } else { aTarget = (object->Copy()); } } } SubstBehaviour::SubstBehaviour(LispEnvironment& aEnvironment, LispPtr& aToMatch, LispPtr& aToReplaceWith) : iEnvironment(aEnvironment), iToMatch(aToMatch), iToReplaceWith(aToReplaceWith) { } bool SubstBehaviour::Matches(LispPtr& aResult, LispPtr& aElement) { if (InternalEquals(iEnvironment, aElement, iToMatch)) { aResult = iToReplaceWith->Copy(); return true; } return false; } LocalSymbolBehaviour::LocalSymbolBehaviour( LispEnvironment& aEnvironment, const std::vector&& aOriginalNames, const std::vector&& aNewNames) : iEnvironment(aEnvironment), iOriginalNames(aOriginalNames), iNewNames(aNewNames) { } bool LocalSymbolBehaviour::Matches(LispPtr& aResult, LispPtr& aElement) { const LispString* name = aElement->String(); if (!name) return false; const std::size_t iNrNames = iOriginalNames.size(); for (std::size_t i = 0; i < iNrNames; ++i) if (name == iOriginalNames[i]) { aResult = LispAtom::New(iEnvironment, *iNewNames[i]); return true; } return false; } bool BackQuoteBehaviour::Matches(LispPtr& aResult, LispPtr& aElement) { if (!aElement->SubList()) return false; LispObject* ptr = (*aElement->SubList()); if (!ptr) return false; if (!ptr->String()) return false; if (*ptr->String() == "`") { aResult = (aElement); return true; } if (*ptr->String() != "@") return false; ptr = ptr->Nixed(); if (!ptr) return false; if (ptr->String()) { LispPtr cur(ptr); /* LispPtr result; iEnvironment.iEvaluator->Eval(iEnvironment, result, cur); InternalSubstitute(aResult, result,*this); */ iEnvironment.iEvaluator->Eval(iEnvironment, aResult, cur); return true; } else { ptr = (*ptr->SubList()); LispPtr cur(ptr); LispPtr args(ptr->Nixed()); LispPtr result; iEnvironment.iEvaluator->Eval(iEnvironment, result, cur); result->Nixed() = (args); LispPtr result2(LispSubList::New(result)); InternalSubstitute(aResult, result2, *this); return true; } return false; } ================================================ FILE: cyacas/libyacas/src/tokenizer.cpp ================================================ #include "yacas/tokenizer.h" #include "yacas/lisperror.h" #include "yacas/utf8.h" #include namespace { static const char symbolics[] = "~`!@#$^&*-=+:<>?/\\|"; // Ll and Lu categories combined // see http://www.fileformat.info/info/unicode/category/index.htm static const std::unordered_set letters = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xb5, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, 0x10c, 0x10d, 0x10e, 0x10f, 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, 0x11a, 0x11b, 0x11c, 0x11d, 0x11e, 0x11f, 0x120, 0x121, 0x122, 0x123, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12a, 0x12b, 0x12c, 0x12d, 0x12e, 0x12f, 0x130, 0x131, 0x132, 0x133, 0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13a, 0x13b, 0x13c, 0x13d, 0x13e, 0x13f, 0x140, 0x141, 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14a, 0x14b, 0x14c, 0x14d, 0x14e, 0x14f, 0x150, 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, 0x15a, 0x15b, 0x15c, 0x15d, 0x15e, 0x15f, 0x160, 0x161, 0x162, 0x163, 0x164, 0x165, 0x166, 0x167, 0x168, 0x169, 0x16a, 0x16b, 0x16c, 0x16d, 0x16e, 0x16f, 0x170, 0x171, 0x172, 0x173, 0x174, 0x175, 0x176, 0x177, 0x178, 0x179, 0x17a, 0x17b, 0x17c, 0x17d, 0x17e, 0x17f, 0x180, 0x181, 0x182, 0x183, 0x184, 0x185, 0x186, 0x187, 0x188, 0x189, 0x18a, 0x18b, 0x18c, 0x18d, 0x18e, 0x18f, 0x190, 0x191, 0x192, 0x193, 0x194, 0x195, 0x196, 0x197, 0x198, 0x199, 0x19a, 0x19b, 0x19c, 0x19d, 0x19e, 0x19f, 0x1a0, 0x1a1, 0x1a2, 0x1a3, 0x1a4, 0x1a5, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1aa, 0x1ab, 0x1ac, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b1, 0x1b2, 0x1b3, 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8, 0x1b9, 0x1ba, 0x1bc, 0x1bd, 0x1be, 0x1bf, 0x1c4, 0x1c6, 0x1c7, 0x1c9, 0x1ca, 0x1cc, 0x1cd, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1df, 0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e6, 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f3, 0x1f4, 0x1f5, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc, 0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, 0x20c, 0x20d, 0x20e, 0x20f, 0x210, 0x211, 0x212, 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, 0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222, 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232, 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, 0x241, 0x242, 0x243, 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, 0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, 0x25d, 0x25e, 0x25f, 0x260, 0x261, 0x262, 0x263, 0x264, 0x265, 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26b, 0x26c, 0x26d, 0x26e, 0x26f, 0x270, 0x271, 0x272, 0x273, 0x274, 0x275, 0x276, 0x277, 0x278, 0x279, 0x27a, 0x27b, 0x27c, 0x27d, 0x27e, 0x27f, 0x280, 0x281, 0x282, 0x283, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, 0x28a, 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x291, 0x292, 0x293, 0x295, 0x296, 0x297, 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7, 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af, 0x370, 0x371, 0x372, 0x373, 0x376, 0x377, 0x37b, 0x37c, 0x37d, 0x37f, 0x386, 0x388, 0x389, 0x38a, 0x38c, 0x38e, 0x38f, 0x390, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39a, 0x39b, 0x39c, 0x39d, 0x39e, 0x39f, 0x3a0, 0x3a1, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, 0x3a8, 0x3a9, 0x3aa, 0x3ab, 0x3ac, 0x3ad, 0x3ae, 0x3af, 0x3b0, 0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b7, 0x3b8, 0x3b9, 0x3ba, 0x3bb, 0x3bc, 0x3bd, 0x3be, 0x3bf, 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7, 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x3cc, 0x3cd, 0x3ce, 0x3cf, 0x3d0, 0x3d1, 0x3d2, 0x3d3, 0x3d4, 0x3d5, 0x3d6, 0x3d7, 0x3d8, 0x3d9, 0x3da, 0x3db, 0x3dc, 0x3dd, 0x3de, 0x3df, 0x3e0, 0x3e1, 0x3e2, 0x3e3, 0x3e4, 0x3e5, 0x3e6, 0x3e7, 0x3e8, 0x3e9, 0x3ea, 0x3eb, 0x3ec, 0x3ed, 0x3ee, 0x3ef, 0x3f0, 0x3f1, 0x3f2, 0x3f3, 0x3f4, 0x3f5, 0x3f7, 0x3f8, 0x3f9, 0x3fa, 0x3fb, 0x3fc, 0x3fd, 0x3fe, 0x3ff, 0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41a, 0x41b, 0x41c, 0x41d, 0x41e, 0x41f, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42a, 0x42b, 0x42c, 0x42d, 0x42e, 0x42f, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43a, 0x43b, 0x43c, 0x43d, 0x43e, 0x43f, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44a, 0x44b, 0x44c, 0x44d, 0x44e, 0x44f, 0x450, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45a, 0x45b, 0x45c, 0x45d, 0x45e, 0x45f, 0x460, 0x461, 0x462, 0x463, 0x464, 0x465, 0x466, 0x467, 0x468, 0x469, 0x46a, 0x46b, 0x46c, 0x46d, 0x46e, 0x46f, 0x470, 0x471, 0x472, 0x473, 0x474, 0x475, 0x476, 0x477, 0x478, 0x479, 0x47a, 0x47b, 0x47c, 0x47d, 0x47e, 0x47f, 0x480, 0x481, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e, 0x48f, 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0x496, 0x497, 0x498, 0x499, 0x49a, 0x49b, 0x49c, 0x49d, 0x49e, 0x49f, 0x4a0, 0x4a1, 0x4a2, 0x4a3, 0x4a4, 0x4a5, 0x4a6, 0x4a7, 0x4a8, 0x4a9, 0x4aa, 0x4ab, 0x4ac, 0x4ad, 0x4ae, 0x4af, 0x4b0, 0x4b1, 0x4b2, 0x4b3, 0x4b4, 0x4b5, 0x4b6, 0x4b7, 0x4b8, 0x4b9, 0x4ba, 0x4bb, 0x4bc, 0x4bd, 0x4be, 0x4bf, 0x4c0, 0x4c1, 0x4c2, 0x4c3, 0x4c4, 0x4c5, 0x4c6, 0x4c7, 0x4c8, 0x4c9, 0x4ca, 0x4cb, 0x4cc, 0x4cd, 0x4ce, 0x4cf, 0x4d0, 0x4d1, 0x4d2, 0x4d3, 0x4d4, 0x4d5, 0x4d6, 0x4d7, 0x4d8, 0x4d9, 0x4da, 0x4db, 0x4dc, 0x4dd, 0x4de, 0x4df, 0x4e0, 0x4e1, 0x4e2, 0x4e3, 0x4e4, 0x4e5, 0x4e6, 0x4e7, 0x4e8, 0x4e9, 0x4ea, 0x4eb, 0x4ec, 0x4ed, 0x4ee, 0x4ef, 0x4f0, 0x4f1, 0x4f2, 0x4f3, 0x4f4, 0x4f5, 0x4f6, 0x4f7, 0x4f8, 0x4f9, 0x4fa, 0x4fb, 0x4fc, 0x4fd, 0x4fe, 0x4ff, 0x500, 0x501, 0x502, 0x503, 0x504, 0x505, 0x506, 0x507, 0x508, 0x509, 0x50a, 0x50b, 0x50c, 0x50d, 0x50e, 0x50f, 0x510, 0x511, 0x512, 0x513, 0x514, 0x515, 0x516, 0x517, 0x518, 0x519, 0x51a, 0x51b, 0x51c, 0x51d, 0x51e, 0x51f, 0x520, 0x521, 0x522, 0x523, 0x524, 0x525, 0x526, 0x527, 0x528, 0x529, 0x52a, 0x52b, 0x52c, 0x52d, 0x52e, 0x52f, 0x531, 0x532, 0x533, 0x534, 0x535, 0x536, 0x537, 0x538, 0x539, 0x53a, 0x53b, 0x53c, 0x53d, 0x53e, 0x53f, 0x540, 0x541, 0x542, 0x543, 0x544, 0x545, 0x546, 0x547, 0x548, 0x549, 0x54a, 0x54b, 0x54c, 0x54d, 0x54e, 0x54f, 0x550, 0x551, 0x552, 0x553, 0x554, 0x555, 0x556, 0x561, 0x562, 0x563, 0x564, 0x565, 0x566, 0x567, 0x568, 0x569, 0x56a, 0x56b, 0x56c, 0x56d, 0x56e, 0x56f, 0x570, 0x571, 0x572, 0x573, 0x574, 0x575, 0x576, 0x577, 0x578, 0x579, 0x57a, 0x57b, 0x57c, 0x57d, 0x57e, 0x57f, 0x580, 0x581, 0x582, 0x583, 0x584, 0x585, 0x586, 0x587, 0x10a0, 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0, 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8, 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0, 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0x10c7, 0x10cd, 0x13a0, 0x13a1, 0x13a2, 0x13a3, 0x13a4, 0x13a5, 0x13a6, 0x13a7, 0x13a8, 0x13a9, 0x13aa, 0x13ab, 0x13ac, 0x13ad, 0x13ae, 0x13af, 0x13b0, 0x13b1, 0x13b2, 0x13b3, 0x13b4, 0x13b5, 0x13b6, 0x13b7, 0x13b8, 0x13b9, 0x13ba, 0x13bb, 0x13bc, 0x13bd, 0x13be, 0x13bf, 0x13c0, 0x13c1, 0x13c2, 0x13c3, 0x13c4, 0x13c5, 0x13c6, 0x13c7, 0x13c8, 0x13c9, 0x13ca, 0x13cb, 0x13cc, 0x13cd, 0x13ce, 0x13cf, 0x13d0, 0x13d1, 0x13d2, 0x13d3, 0x13d4, 0x13d5, 0x13d6, 0x13d7, 0x13d8, 0x13d9, 0x13da, 0x13db, 0x13dc, 0x13dd, 0x13de, 0x13df, 0x13e0, 0x13e1, 0x13e2, 0x13e3, 0x13e4, 0x13e5, 0x13e6, 0x13e7, 0x13e8, 0x13e9, 0x13ea, 0x13eb, 0x13ec, 0x13ed, 0x13ee, 0x13ef, 0x13f0, 0x13f1, 0x13f2, 0x13f3, 0x13f4, 0x13f5, 0x13f8, 0x13f9, 0x13fa, 0x13fb, 0x13fc, 0x13fd, 0x1d00, 0x1d01, 0x1d02, 0x1d03, 0x1d04, 0x1d05, 0x1d06, 0x1d07, 0x1d08, 0x1d09, 0x1d0a, 0x1d0b, 0x1d0c, 0x1d0d, 0x1d0e, 0x1d0f, 0x1d10, 0x1d11, 0x1d12, 0x1d13, 0x1d14, 0x1d15, 0x1d16, 0x1d17, 0x1d18, 0x1d19, 0x1d1a, 0x1d1b, 0x1d1c, 0x1d1d, 0x1d1e, 0x1d1f, 0x1d20, 0x1d21, 0x1d22, 0x1d23, 0x1d24, 0x1d25, 0x1d26, 0x1d27, 0x1d28, 0x1d29, 0x1d2a, 0x1d2b, 0x1d6b, 0x1d6c, 0x1d6d, 0x1d6e, 0x1d6f, 0x1d70, 0x1d71, 0x1d72, 0x1d73, 0x1d74, 0x1d75, 0x1d76, 0x1d77, 0x1d79, 0x1d7a, 0x1d7b, 0x1d7c, 0x1d7d, 0x1d7e, 0x1d7f, 0x1d80, 0x1d81, 0x1d82, 0x1d83, 0x1d84, 0x1d85, 0x1d86, 0x1d87, 0x1d88, 0x1d89, 0x1d8a, 0x1d8b, 0x1d8c, 0x1d8d, 0x1d8e, 0x1d8f, 0x1d90, 0x1d91, 0x1d92, 0x1d93, 0x1d94, 0x1d95, 0x1d96, 0x1d97, 0x1d98, 0x1d99, 0x1d9a, 0x1e00, 0x1e01, 0x1e02, 0x1e03, 0x1e04, 0x1e05, 0x1e06, 0x1e07, 0x1e08, 0x1e09, 0x1e0a, 0x1e0b, 0x1e0c, 0x1e0d, 0x1e0e, 0x1e0f, 0x1e10, 0x1e11, 0x1e12, 0x1e13, 0x1e14, 0x1e15, 0x1e16, 0x1e17, 0x1e18, 0x1e19, 0x1e1a, 0x1e1b, 0x1e1c, 0x1e1d, 0x1e1e, 0x1e1f, 0x1e20, 0x1e21, 0x1e22, 0x1e23, 0x1e24, 0x1e25, 0x1e26, 0x1e27, 0x1e28, 0x1e29, 0x1e2a, 0x1e2b, 0x1e2c, 0x1e2d, 0x1e2e, 0x1e2f, 0x1e30, 0x1e31, 0x1e32, 0x1e33, 0x1e34, 0x1e35, 0x1e36, 0x1e37, 0x1e38, 0x1e39, 0x1e3a, 0x1e3b, 0x1e3c, 0x1e3d, 0x1e3e, 0x1e3f, 0x1e40, 0x1e41, 0x1e42, 0x1e43, 0x1e44, 0x1e45, 0x1e46, 0x1e47, 0x1e48, 0x1e49, 0x1e4a, 0x1e4b, 0x1e4c, 0x1e4d, 0x1e4e, 0x1e4f, 0x1e50, 0x1e51, 0x1e52, 0x1e53, 0x1e54, 0x1e55, 0x1e56, 0x1e57, 0x1e58, 0x1e59, 0x1e5a, 0x1e5b, 0x1e5c, 0x1e5d, 0x1e5e, 0x1e5f, 0x1e60, 0x1e61, 0x1e62, 0x1e63, 0x1e64, 0x1e65, 0x1e66, 0x1e67, 0x1e68, 0x1e69, 0x1e6a, 0x1e6b, 0x1e6c, 0x1e6d, 0x1e6e, 0x1e6f, 0x1e70, 0x1e71, 0x1e72, 0x1e73, 0x1e74, 0x1e75, 0x1e76, 0x1e77, 0x1e78, 0x1e79, 0x1e7a, 0x1e7b, 0x1e7c, 0x1e7d, 0x1e7e, 0x1e7f, 0x1e80, 0x1e81, 0x1e82, 0x1e83, 0x1e84, 0x1e85, 0x1e86, 0x1e87, 0x1e88, 0x1e89, 0x1e8a, 0x1e8b, 0x1e8c, 0x1e8d, 0x1e8e, 0x1e8f, 0x1e90, 0x1e91, 0x1e92, 0x1e93, 0x1e94, 0x1e95, 0x1e96, 0x1e97, 0x1e98, 0x1e99, 0x1e9a, 0x1e9b, 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, 0x1ea0, 0x1ea1, 0x1ea2, 0x1ea3, 0x1ea4, 0x1ea5, 0x1ea6, 0x1ea7, 0x1ea8, 0x1ea9, 0x1eaa, 0x1eab, 0x1eac, 0x1ead, 0x1eae, 0x1eaf, 0x1eb0, 0x1eb1, 0x1eb2, 0x1eb3, 0x1eb4, 0x1eb5, 0x1eb6, 0x1eb7, 0x1eb8, 0x1eb9, 0x1eba, 0x1ebb, 0x1ebc, 0x1ebd, 0x1ebe, 0x1ebf, 0x1ec0, 0x1ec1, 0x1ec2, 0x1ec3, 0x1ec4, 0x1ec5, 0x1ec6, 0x1ec7, 0x1ec8, 0x1ec9, 0x1eca, 0x1ecb, 0x1ecc, 0x1ecd, 0x1ece, 0x1ecf, 0x1ed0, 0x1ed1, 0x1ed2, 0x1ed3, 0x1ed4, 0x1ed5, 0x1ed6, 0x1ed7, 0x1ed8, 0x1ed9, 0x1eda, 0x1edb, 0x1edc, 0x1edd, 0x1ede, 0x1edf, 0x1ee0, 0x1ee1, 0x1ee2, 0x1ee3, 0x1ee4, 0x1ee5, 0x1ee6, 0x1ee7, 0x1ee8, 0x1ee9, 0x1eea, 0x1eeb, 0x1eec, 0x1eed, 0x1eee, 0x1eef, 0x1ef0, 0x1ef1, 0x1ef2, 0x1ef3, 0x1ef4, 0x1ef5, 0x1ef6, 0x1ef7, 0x1ef8, 0x1ef9, 0x1efa, 0x1efb, 0x1efc, 0x1efd, 0x1efe, 0x1eff, 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0x1f50, 0x1f51, 0x1f52, 0x1f53, 0x1f54, 0x1f55, 0x1f56, 0x1f57, 0x1f59, 0x1f5b, 0x1f5d, 0x1f5f, 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1f70, 0x1f71, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1f76, 0x1f77, 0x1f78, 0x1f79, 0x1f7a, 0x1f7b, 0x1f7c, 0x1f7d, 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, 0x1fb0, 0x1fb1, 0x1fb2, 0x1fb3, 0x1fb4, 0x1fb6, 0x1fb7, 0x1fb8, 0x1fb9, 0x1fba, 0x1fbb, 0x1fbe, 0x1fc2, 0x1fc3, 0x1fc4, 0x1fc6, 0x1fc7, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fd0, 0x1fd1, 0x1fd2, 0x1fd3, 0x1fd6, 0x1fd7, 0x1fd8, 0x1fd9, 0x1fda, 0x1fdb, 0x1fe0, 0x1fe1, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe5, 0x1fe6, 0x1fe7, 0x1fe8, 0x1fe9, 0x1fea, 0x1feb, 0x1fec, 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff6, 0x1ff7, 0x1ff8, 0x1ff9, 0x1ffa, 0x1ffb, 0x2102, 0x2107, 0x210a, 0x210b, 0x210c, 0x210d, 0x210e, 0x210f, 0x2110, 0x2111, 0x2112, 0x2113, 0x2115, 0x2119, 0x211a, 0x211b, 0x211c, 0x211d, 0x2124, 0x2126, 0x2128, 0x212a, 0x212b, 0x212c, 0x212d, 0x212f, 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2139, 0x213c, 0x213d, 0x213e, 0x213f, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214e, 0x2183, 0x2184, 0x2c00, 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x2c08, 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x2c10, 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17, 0x2c18, 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f, 0x2c20, 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27, 0x2c28, 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x2c30, 0x2c31, 0x2c32, 0x2c33, 0x2c34, 0x2c35, 0x2c36, 0x2c37, 0x2c38, 0x2c39, 0x2c3a, 0x2c3b, 0x2c3c, 0x2c3d, 0x2c3e, 0x2c3f, 0x2c40, 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2c48, 0x2c49, 0x2c4a, 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c50, 0x2c51, 0x2c52, 0x2c53, 0x2c54, 0x2c55, 0x2c56, 0x2c57, 0x2c58, 0x2c59, 0x2c5a, 0x2c5b, 0x2c5c, 0x2c5d, 0x2c5e, 0x2c60, 0x2c61, 0x2c62, 0x2c63, 0x2c64, 0x2c65, 0x2c66, 0x2c67, 0x2c68, 0x2c69, 0x2c6a, 0x2c6b, 0x2c6c, 0x2c6d, 0x2c6e, 0x2c6f, 0x2c70, 0x2c71, 0x2c72, 0x2c73, 0x2c74, 0x2c75, 0x2c76, 0x2c77, 0x2c78, 0x2c79, 0x2c7a, 0x2c7b, 0x2c7e, 0x2c7f, 0x2c80, 0x2c81, 0x2c82, 0x2c83, 0x2c84, 0x2c85, 0x2c86, 0x2c87, 0x2c88, 0x2c89, 0x2c8a, 0x2c8b, 0x2c8c, 0x2c8d, 0x2c8e, 0x2c8f, 0x2c90, 0x2c91, 0x2c92, 0x2c93, 0x2c94, 0x2c95, 0x2c96, 0x2c97, 0x2c98, 0x2c99, 0x2c9a, 0x2c9b, 0x2c9c, 0x2c9d, 0x2c9e, 0x2c9f, 0x2ca0, 0x2ca1, 0x2ca2, 0x2ca3, 0x2ca4, 0x2ca5, 0x2ca6, 0x2ca7, 0x2ca8, 0x2ca9, 0x2caa, 0x2cab, 0x2cac, 0x2cad, 0x2cae, 0x2caf, 0x2cb0, 0x2cb1, 0x2cb2, 0x2cb3, 0x2cb4, 0x2cb5, 0x2cb6, 0x2cb7, 0x2cb8, 0x2cb9, 0x2cba, 0x2cbb, 0x2cbc, 0x2cbd, 0x2cbe, 0x2cbf, 0x2cc0, 0x2cc1, 0x2cc2, 0x2cc3, 0x2cc4, 0x2cc5, 0x2cc6, 0x2cc7, 0x2cc8, 0x2cc9, 0x2cca, 0x2ccb, 0x2ccc, 0x2ccd, 0x2cce, 0x2ccf, 0x2cd0, 0x2cd1, 0x2cd2, 0x2cd3, 0x2cd4, 0x2cd5, 0x2cd6, 0x2cd7, 0x2cd8, 0x2cd9, 0x2cda, 0x2cdb, 0x2cdc, 0x2cdd, 0x2cde, 0x2cdf, 0x2ce0, 0x2ce1, 0x2ce2, 0x2ce3, 0x2ce4, 0x2ceb, 0x2cec, 0x2ced, 0x2cee, 0x2cf2, 0x2cf3, 0x2d00, 0x2d01, 0x2d02, 0x2d03, 0x2d04, 0x2d05, 0x2d06, 0x2d07, 0x2d08, 0x2d09, 0x2d0a, 0x2d0b, 0x2d0c, 0x2d0d, 0x2d0e, 0x2d0f, 0x2d10, 0x2d11, 0x2d12, 0x2d13, 0x2d14, 0x2d15, 0x2d16, 0x2d17, 0x2d18, 0x2d19, 0x2d1a, 0x2d1b, 0x2d1c, 0x2d1d, 0x2d1e, 0x2d1f, 0x2d20, 0x2d21, 0x2d22, 0x2d23, 0x2d24, 0x2d25, 0x2d27, 0x2d2d, 0xa640, 0xa641, 0xa642, 0xa643, 0xa644, 0xa645, 0xa646, 0xa647, 0xa648, 0xa649, 0xa64a, 0xa64b, 0xa64c, 0xa64d, 0xa64e, 0xa64f, 0xa650, 0xa651, 0xa652, 0xa653, 0xa654, 0xa655, 0xa656, 0xa657, 0xa658, 0xa659, 0xa65a, 0xa65b, 0xa65c, 0xa65d, 0xa65e, 0xa65f, 0xa660, 0xa661, 0xa662, 0xa663, 0xa664, 0xa665, 0xa666, 0xa667, 0xa668, 0xa669, 0xa66a, 0xa66b, 0xa66c, 0xa66d, 0xa680, 0xa681, 0xa682, 0xa683, 0xa684, 0xa685, 0xa686, 0xa687, 0xa688, 0xa689, 0xa68a, 0xa68b, 0xa68c, 0xa68d, 0xa68e, 0xa68f, 0xa690, 0xa691, 0xa692, 0xa693, 0xa694, 0xa695, 0xa696, 0xa697, 0xa698, 0xa699, 0xa69a, 0xa69b, 0xa722, 0xa723, 0xa724, 0xa725, 0xa726, 0xa727, 0xa728, 0xa729, 0xa72a, 0xa72b, 0xa72c, 0xa72d, 0xa72e, 0xa72f, 0xa730, 0xa731, 0xa732, 0xa733, 0xa734, 0xa735, 0xa736, 0xa737, 0xa738, 0xa739, 0xa73a, 0xa73b, 0xa73c, 0xa73d, 0xa73e, 0xa73f, 0xa740, 0xa741, 0xa742, 0xa743, 0xa744, 0xa745, 0xa746, 0xa747, 0xa748, 0xa749, 0xa74a, 0xa74b, 0xa74c, 0xa74d, 0xa74e, 0xa74f, 0xa750, 0xa751, 0xa752, 0xa753, 0xa754, 0xa755, 0xa756, 0xa757, 0xa758, 0xa759, 0xa75a, 0xa75b, 0xa75c, 0xa75d, 0xa75e, 0xa75f, 0xa760, 0xa761, 0xa762, 0xa763, 0xa764, 0xa765, 0xa766, 0xa767, 0xa768, 0xa769, 0xa76a, 0xa76b, 0xa76c, 0xa76d, 0xa76e, 0xa76f, 0xa771, 0xa772, 0xa773, 0xa774, 0xa775, 0xa776, 0xa777, 0xa778, 0xa779, 0xa77a, 0xa77b, 0xa77c, 0xa77d, 0xa77e, 0xa77f, 0xa780, 0xa781, 0xa782, 0xa783, 0xa784, 0xa785, 0xa786, 0xa787, 0xa78b, 0xa78c, 0xa78d, 0xa78e, 0xa790, 0xa791, 0xa792, 0xa793, 0xa794, 0xa795, 0xa796, 0xa797, 0xa798, 0xa799, 0xa79a, 0xa79b, 0xa79c, 0xa79d, 0xa79e, 0xa79f, 0xa7a0, 0xa7a1, 0xa7a2, 0xa7a3, 0xa7a4, 0xa7a5, 0xa7a6, 0xa7a7, 0xa7a8, 0xa7a9, 0xa7aa, 0xa7ab, 0xa7ac, 0xa7ad, 0xa7b0, 0xa7b1, 0xa7b2, 0xa7b3, 0xa7b4, 0xa7b5, 0xa7b6, 0xa7b7, 0xa7fa, 0xab30, 0xab31, 0xab32, 0xab33, 0xab34, 0xab35, 0xab36, 0xab37, 0xab38, 0xab39, 0xab3a, 0xab3b, 0xab3c, 0xab3d, 0xab3e, 0xab3f, 0xab40, 0xab41, 0xab42, 0xab43, 0xab44, 0xab45, 0xab46, 0xab47, 0xab48, 0xab49, 0xab4a, 0xab4b, 0xab4c, 0xab4d, 0xab4e, 0xab4f, 0xab50, 0xab51, 0xab52, 0xab53, 0xab54, 0xab55, 0xab56, 0xab57, 0xab58, 0xab59, 0xab5a, 0xab60, 0xab61, 0xab62, 0xab63, 0xab64, 0xab65, 0xab70, 0xab71, 0xab72, 0xab73, 0xab74, 0xab75, 0xab76, 0xab77, 0xab78, 0xab79, 0xab7a, 0xab7b, 0xab7c, 0xab7d, 0xab7e, 0xab7f, 0xab80, 0xab81, 0xab82, 0xab83, 0xab84, 0xab85, 0xab86, 0xab87, 0xab88, 0xab89, 0xab8a, 0xab8b, 0xab8c, 0xab8d, 0xab8e, 0xab8f, 0xab90, 0xab91, 0xab92, 0xab93, 0xab94, 0xab95, 0xab96, 0xab97, 0xab98, 0xab99, 0xab9a, 0xab9b, 0xab9c, 0xab9d, 0xab9e, 0xab9f, 0xaba0, 0xaba1, 0xaba2, 0xaba3, 0xaba4, 0xaba5, 0xaba6, 0xaba7, 0xaba8, 0xaba9, 0xabaa, 0xabab, 0xabac, 0xabad, 0xabae, 0xabaf, 0xabb0, 0xabb1, 0xabb2, 0xabb3, 0xabb4, 0xabb5, 0xabb6, 0xabb7, 0xabb8, 0xabb9, 0xabba, 0xabbb, 0xabbc, 0xabbd, 0xabbe, 0xabbf, 0xfb00, 0xfb01, 0xfb02, 0xfb03, 0xfb04, 0xfb05, 0xfb06, 0xfb13, 0xfb14, 0xfb15, 0xfb16, 0xfb17, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, 0xff3a, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, 0xff58, 0xff59, 0xff5a, 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407, 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f, 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417, 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f, 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427, 0x10428, 0x10429, 0x1042a, 0x1042b, 0x1042c, 0x1042d, 0x1042e, 0x1042f, 0x10430, 0x10431, 0x10432, 0x10433, 0x10434, 0x10435, 0x10436, 0x10437, 0x10438, 0x10439, 0x1043a, 0x1043b, 0x1043c, 0x1043d, 0x1043e, 0x1043f, 0x10440, 0x10441, 0x10442, 0x10443, 0x10444, 0x10445, 0x10446, 0x10447, 0x10448, 0x10449, 0x1044a, 0x1044b, 0x1044c, 0x1044d, 0x1044e, 0x1044f, 0x10c80, 0x10c81, 0x10c82, 0x10c83, 0x10c84, 0x10c85, 0x10c86, 0x10c87, 0x10c88, 0x10c89, 0x10c8a, 0x10c8b, 0x10c8c, 0x10c8d, 0x10c8e, 0x10c8f, 0x10c90, 0x10c91, 0x10c92, 0x10c93, 0x10c94, 0x10c95, 0x10c96, 0x10c97, 0x10c98, 0x10c99, 0x10c9a, 0x10c9b, 0x10c9c, 0x10c9d, 0x10c9e, 0x10c9f, 0x10ca0, 0x10ca1, 0x10ca2, 0x10ca3, 0x10ca4, 0x10ca5, 0x10ca6, 0x10ca7, 0x10ca8, 0x10ca9, 0x10caa, 0x10cab, 0x10cac, 0x10cad, 0x10cae, 0x10caf, 0x10cb0, 0x10cb1, 0x10cb2, 0x10cc0, 0x10cc1, 0x10cc2, 0x10cc3, 0x10cc4, 0x10cc5, 0x10cc6, 0x10cc7, 0x10cc8, 0x10cc9, 0x10cca, 0x10ccb, 0x10ccc, 0x10ccd, 0x10cce, 0x10ccf, 0x10cd0, 0x10cd1, 0x10cd2, 0x10cd3, 0x10cd4, 0x10cd5, 0x10cd6, 0x10cd7, 0x10cd8, 0x10cd9, 0x10cda, 0x10cdb, 0x10cdc, 0x10cdd, 0x10cde, 0x10cdf, 0x10ce0, 0x10ce1, 0x10ce2, 0x10ce3, 0x10ce4, 0x10ce5, 0x10ce6, 0x10ce7, 0x10ce8, 0x10ce9, 0x10cea, 0x10ceb, 0x10cec, 0x10ced, 0x10cee, 0x10cef, 0x10cf0, 0x10cf1, 0x10cf2, 0x118a0, 0x118a1, 0x118a2, 0x118a3, 0x118a4, 0x118a5, 0x118a6, 0x118a7, 0x118a8, 0x118a9, 0x118aa, 0x118ab, 0x118ac, 0x118ad, 0x118ae, 0x118af, 0x118b0, 0x118b1, 0x118b2, 0x118b3, 0x118b4, 0x118b5, 0x118b6, 0x118b7, 0x118b8, 0x118b9, 0x118ba, 0x118bb, 0x118bc, 0x118bd, 0x118be, 0x118bf, 0x118c0, 0x118c1, 0x118c2, 0x118c3, 0x118c4, 0x118c5, 0x118c6, 0x118c7, 0x118c8, 0x118c9, 0x118ca, 0x118cb, 0x118cc, 0x118cd, 0x118ce, 0x118cf, 0x118d0, 0x118d1, 0x118d2, 0x118d3, 0x118d4, 0x118d5, 0x118d6, 0x118d7, 0x118d8, 0x118d9, 0x118da, 0x118db, 0x118dc, 0x118dd, 0x118de, 0x118df, 0x1d400, 0x1d401, 0x1d402, 0x1d403, 0x1d404, 0x1d405, 0x1d406, 0x1d407, 0x1d408, 0x1d409, 0x1d40a, 0x1d40b, 0x1d40c, 0x1d40d, 0x1d40e, 0x1d40f, 0x1d410, 0x1d411, 0x1d412, 0x1d413, 0x1d414, 0x1d415, 0x1d416, 0x1d417, 0x1d418, 0x1d419, 0x1d41a, 0x1d41b, 0x1d41c, 0x1d41d, 0x1d41e, 0x1d41f, 0x1d420, 0x1d421, 0x1d422, 0x1d423, 0x1d424, 0x1d425, 0x1d426, 0x1d427, 0x1d428, 0x1d429, 0x1d42a, 0x1d42b, 0x1d42c, 0x1d42d, 0x1d42e, 0x1d42f, 0x1d430, 0x1d431, 0x1d432, 0x1d433, 0x1d434, 0x1d435, 0x1d436, 0x1d437, 0x1d438, 0x1d439, 0x1d43a, 0x1d43b, 0x1d43c, 0x1d43d, 0x1d43e, 0x1d43f, 0x1d440, 0x1d441, 0x1d442, 0x1d443, 0x1d444, 0x1d445, 0x1d446, 0x1d447, 0x1d448, 0x1d449, 0x1d44a, 0x1d44b, 0x1d44c, 0x1d44d, 0x1d44e, 0x1d44f, 0x1d450, 0x1d451, 0x1d452, 0x1d453, 0x1d454, 0x1d456, 0x1d457, 0x1d458, 0x1d459, 0x1d45a, 0x1d45b, 0x1d45c, 0x1d45d, 0x1d45e, 0x1d45f, 0x1d460, 0x1d461, 0x1d462, 0x1d463, 0x1d464, 0x1d465, 0x1d466, 0x1d467, 0x1d468, 0x1d469, 0x1d46a, 0x1d46b, 0x1d46c, 0x1d46d, 0x1d46e, 0x1d46f, 0x1d470, 0x1d471, 0x1d472, 0x1d473, 0x1d474, 0x1d475, 0x1d476, 0x1d477, 0x1d478, 0x1d479, 0x1d47a, 0x1d47b, 0x1d47c, 0x1d47d, 0x1d47e, 0x1d47f, 0x1d480, 0x1d481, 0x1d482, 0x1d483, 0x1d484, 0x1d485, 0x1d486, 0x1d487, 0x1d488, 0x1d489, 0x1d48a, 0x1d48b, 0x1d48c, 0x1d48d, 0x1d48e, 0x1d48f, 0x1d490, 0x1d491, 0x1d492, 0x1d493, 0x1d494, 0x1d495, 0x1d496, 0x1d497, 0x1d498, 0x1d499, 0x1d49a, 0x1d49b, 0x1d49c, 0x1d49e, 0x1d49f, 0x1d4a2, 0x1d4a5, 0x1d4a6, 0x1d4a9, 0x1d4aa, 0x1d4ab, 0x1d4ac, 0x1d4ae, 0x1d4af, 0x1d4b0, 0x1d4b1, 0x1d4b2, 0x1d4b3, 0x1d4b4, 0x1d4b5, 0x1d4b6, 0x1d4b7, 0x1d4b8, 0x1d4b9, 0x1d4bb, 0x1d4bd, 0x1d4be, 0x1d4bf, 0x1d4c0, 0x1d4c1, 0x1d4c2, 0x1d4c3, 0x1d4c5, 0x1d4c6, 0x1d4c7, 0x1d4c8, 0x1d4c9, 0x1d4ca, 0x1d4cb, 0x1d4cc, 0x1d4cd, 0x1d4ce, 0x1d4cf, 0x1d4d0, 0x1d4d1, 0x1d4d2, 0x1d4d3, 0x1d4d4, 0x1d4d5, 0x1d4d6, 0x1d4d7, 0x1d4d8, 0x1d4d9, 0x1d4da, 0x1d4db, 0x1d4dc, 0x1d4dd, 0x1d4de, 0x1d4df, 0x1d4e0, 0x1d4e1, 0x1d4e2, 0x1d4e3, 0x1d4e4, 0x1d4e5, 0x1d4e6, 0x1d4e7, 0x1d4e8, 0x1d4e9, 0x1d4ea, 0x1d4eb, 0x1d4ec, 0x1d4ed, 0x1d4ee, 0x1d4ef, 0x1d4f0, 0x1d4f1, 0x1d4f2, 0x1d4f3, 0x1d4f4, 0x1d4f5, 0x1d4f6, 0x1d4f7, 0x1d4f8, 0x1d4f9, 0x1d4fa, 0x1d4fb, 0x1d4fc, 0x1d4fd, 0x1d4fe, 0x1d4ff, 0x1d500, 0x1d501, 0x1d502, 0x1d503, 0x1d504, 0x1d505, 0x1d507, 0x1d508, 0x1d509, 0x1d50a, 0x1d50d, 0x1d50e, 0x1d50f, 0x1d510, 0x1d511, 0x1d512, 0x1d513, 0x1d514, 0x1d516, 0x1d517, 0x1d518, 0x1d519, 0x1d51a, 0x1d51b, 0x1d51c, 0x1d51e, 0x1d51f, 0x1d520, 0x1d521, 0x1d522, 0x1d523, 0x1d524, 0x1d525, 0x1d526, 0x1d527, 0x1d528, 0x1d529, 0x1d52a, 0x1d52b, 0x1d52c, 0x1d52d, 0x1d52e, 0x1d52f, 0x1d530, 0x1d531, 0x1d532, 0x1d533, 0x1d534, 0x1d535, 0x1d536, 0x1d537, 0x1d538, 0x1d539, 0x1d53b, 0x1d53c, 0x1d53d, 0x1d53e, 0x1d540, 0x1d541, 0x1d542, 0x1d543, 0x1d544, 0x1d546, 0x1d54a, 0x1d54b, 0x1d54c, 0x1d54d, 0x1d54e, 0x1d54f, 0x1d550, 0x1d552, 0x1d553, 0x1d554, 0x1d555, 0x1d556, 0x1d557, 0x1d558, 0x1d559, 0x1d55a, 0x1d55b, 0x1d55c, 0x1d55d, 0x1d55e, 0x1d55f, 0x1d560, 0x1d561, 0x1d562, 0x1d563, 0x1d564, 0x1d565, 0x1d566, 0x1d567, 0x1d568, 0x1d569, 0x1d56a, 0x1d56b, 0x1d56c, 0x1d56d, 0x1d56e, 0x1d56f, 0x1d570, 0x1d571, 0x1d572, 0x1d573, 0x1d574, 0x1d575, 0x1d576, 0x1d577, 0x1d578, 0x1d579, 0x1d57a, 0x1d57b, 0x1d57c, 0x1d57d, 0x1d57e, 0x1d57f, 0x1d580, 0x1d581, 0x1d582, 0x1d583, 0x1d584, 0x1d585, 0x1d586, 0x1d587, 0x1d588, 0x1d589, 0x1d58a, 0x1d58b, 0x1d58c, 0x1d58d, 0x1d58e, 0x1d58f, 0x1d590, 0x1d591, 0x1d592, 0x1d593, 0x1d594, 0x1d595, 0x1d596, 0x1d597, 0x1d598, 0x1d599, 0x1d59a, 0x1d59b, 0x1d59c, 0x1d59d, 0x1d59e, 0x1d59f, 0x1d5a0, 0x1d5a1, 0x1d5a2, 0x1d5a3, 0x1d5a4, 0x1d5a5, 0x1d5a6, 0x1d5a7, 0x1d5a8, 0x1d5a9, 0x1d5aa, 0x1d5ab, 0x1d5ac, 0x1d5ad, 0x1d5ae, 0x1d5af, 0x1d5b0, 0x1d5b1, 0x1d5b2, 0x1d5b3, 0x1d5b4, 0x1d5b5, 0x1d5b6, 0x1d5b7, 0x1d5b8, 0x1d5b9, 0x1d5ba, 0x1d5bb, 0x1d5bc, 0x1d5bd, 0x1d5be, 0x1d5bf, 0x1d5c0, 0x1d5c1, 0x1d5c2, 0x1d5c3, 0x1d5c4, 0x1d5c5, 0x1d5c6, 0x1d5c7, 0x1d5c8, 0x1d5c9, 0x1d5ca, 0x1d5cb, 0x1d5cc, 0x1d5cd, 0x1d5ce, 0x1d5cf, 0x1d5d0, 0x1d5d1, 0x1d5d2, 0x1d5d3, 0x1d5d4, 0x1d5d5, 0x1d5d6, 0x1d5d7, 0x1d5d8, 0x1d5d9, 0x1d5da, 0x1d5db, 0x1d5dc, 0x1d5dd, 0x1d5de, 0x1d5df, 0x1d5e0, 0x1d5e1, 0x1d5e2, 0x1d5e3, 0x1d5e4, 0x1d5e5, 0x1d5e6, 0x1d5e7, 0x1d5e8, 0x1d5e9, 0x1d5ea, 0x1d5eb, 0x1d5ec, 0x1d5ed, 0x1d5ee, 0x1d5ef, 0x1d5f0, 0x1d5f1, 0x1d5f2, 0x1d5f3, 0x1d5f4, 0x1d5f5, 0x1d5f6, 0x1d5f7, 0x1d5f8, 0x1d5f9, 0x1d5fa, 0x1d5fb, 0x1d5fc, 0x1d5fd, 0x1d5fe, 0x1d5ff, 0x1d600, 0x1d601, 0x1d602, 0x1d603, 0x1d604, 0x1d605, 0x1d606, 0x1d607, 0x1d608, 0x1d609, 0x1d60a, 0x1d60b, 0x1d60c, 0x1d60d, 0x1d60e, 0x1d60f, 0x1d610, 0x1d611, 0x1d612, 0x1d613, 0x1d614, 0x1d615, 0x1d616, 0x1d617, 0x1d618, 0x1d619, 0x1d61a, 0x1d61b, 0x1d61c, 0x1d61d, 0x1d61e, 0x1d61f, 0x1d620, 0x1d621, 0x1d622, 0x1d623, 0x1d624, 0x1d625, 0x1d626, 0x1d627, 0x1d628, 0x1d629, 0x1d62a, 0x1d62b, 0x1d62c, 0x1d62d, 0x1d62e, 0x1d62f, 0x1d630, 0x1d631, 0x1d632, 0x1d633, 0x1d634, 0x1d635, 0x1d636, 0x1d637, 0x1d638, 0x1d639, 0x1d63a, 0x1d63b, 0x1d63c, 0x1d63d, 0x1d63e, 0x1d63f, 0x1d640, 0x1d641, 0x1d642, 0x1d643, 0x1d644, 0x1d645, 0x1d646, 0x1d647, 0x1d648, 0x1d649, 0x1d64a, 0x1d64b, 0x1d64c, 0x1d64d, 0x1d64e, 0x1d64f, 0x1d650, 0x1d651, 0x1d652, 0x1d653, 0x1d654, 0x1d655, 0x1d656, 0x1d657, 0x1d658, 0x1d659, 0x1d65a, 0x1d65b, 0x1d65c, 0x1d65d, 0x1d65e, 0x1d65f, 0x1d660, 0x1d661, 0x1d662, 0x1d663, 0x1d664, 0x1d665, 0x1d666, 0x1d667, 0x1d668, 0x1d669, 0x1d66a, 0x1d66b, 0x1d66c, 0x1d66d, 0x1d66e, 0x1d66f, 0x1d670, 0x1d671, 0x1d672, 0x1d673, 0x1d674, 0x1d675, 0x1d676, 0x1d677, 0x1d678, 0x1d679, 0x1d67a, 0x1d67b, 0x1d67c, 0x1d67d, 0x1d67e, 0x1d67f, 0x1d680, 0x1d681, 0x1d682, 0x1d683, 0x1d684, 0x1d685, 0x1d686, 0x1d687, 0x1d688, 0x1d689, 0x1d68a, 0x1d68b, 0x1d68c, 0x1d68d, 0x1d68e, 0x1d68f, 0x1d690, 0x1d691, 0x1d692, 0x1d693, 0x1d694, 0x1d695, 0x1d696, 0x1d697, 0x1d698, 0x1d699, 0x1d69a, 0x1d69b, 0x1d69c, 0x1d69d, 0x1d69e, 0x1d69f, 0x1d6a0, 0x1d6a1, 0x1d6a2, 0x1d6a3, 0x1d6a4, 0x1d6a5, 0x1d6a8, 0x1d6a9, 0x1d6aa, 0x1d6ab, 0x1d6ac, 0x1d6ad, 0x1d6ae, 0x1d6af, 0x1d6b0, 0x1d6b1, 0x1d6b2, 0x1d6b3, 0x1d6b4, 0x1d6b5, 0x1d6b6, 0x1d6b7, 0x1d6b8, 0x1d6b9, 0x1d6ba, 0x1d6bb, 0x1d6bc, 0x1d6bd, 0x1d6be, 0x1d6bf, 0x1d6c0, 0x1d6c2, 0x1d6c3, 0x1d6c4, 0x1d6c5, 0x1d6c6, 0x1d6c7, 0x1d6c8, 0x1d6c9, 0x1d6ca, 0x1d6cb, 0x1d6cc, 0x1d6cd, 0x1d6ce, 0x1d6cf, 0x1d6d0, 0x1d6d1, 0x1d6d2, 0x1d6d3, 0x1d6d4, 0x1d6d5, 0x1d6d6, 0x1d6d7, 0x1d6d8, 0x1d6d9, 0x1d6da, 0x1d6dc, 0x1d6dd, 0x1d6de, 0x1d6df, 0x1d6e0, 0x1d6e1, 0x1d6e2, 0x1d6e3, 0x1d6e4, 0x1d6e5, 0x1d6e6, 0x1d6e7, 0x1d6e8, 0x1d6e9, 0x1d6ea, 0x1d6eb, 0x1d6ec, 0x1d6ed, 0x1d6ee, 0x1d6ef, 0x1d6f0, 0x1d6f1, 0x1d6f2, 0x1d6f3, 0x1d6f4, 0x1d6f5, 0x1d6f6, 0x1d6f7, 0x1d6f8, 0x1d6f9, 0x1d6fa, 0x1d6fc, 0x1d6fd, 0x1d6fe, 0x1d6ff, 0x1d700, 0x1d701, 0x1d702, 0x1d703, 0x1d704, 0x1d705, 0x1d706, 0x1d707, 0x1d708, 0x1d709, 0x1d70a, 0x1d70b, 0x1d70c, 0x1d70d, 0x1d70e, 0x1d70f, 0x1d710, 0x1d711, 0x1d712, 0x1d713, 0x1d714, 0x1d716, 0x1d717, 0x1d718, 0x1d719, 0x1d71a, 0x1d71b, 0x1d71c, 0x1d71d, 0x1d71e, 0x1d71f, 0x1d720, 0x1d721, 0x1d722, 0x1d723, 0x1d724, 0x1d725, 0x1d726, 0x1d727, 0x1d728, 0x1d729, 0x1d72a, 0x1d72b, 0x1d72c, 0x1d72d, 0x1d72e, 0x1d72f, 0x1d730, 0x1d731, 0x1d732, 0x1d733, 0x1d734, 0x1d736, 0x1d737, 0x1d738, 0x1d739, 0x1d73a, 0x1d73b, 0x1d73c, 0x1d73d, 0x1d73e, 0x1d73f, 0x1d740, 0x1d741, 0x1d742, 0x1d743, 0x1d744, 0x1d745, 0x1d746, 0x1d747, 0x1d748, 0x1d749, 0x1d74a, 0x1d74b, 0x1d74c, 0x1d74d, 0x1d74e, 0x1d750, 0x1d751, 0x1d752, 0x1d753, 0x1d754, 0x1d755, 0x1d756, 0x1d757, 0x1d758, 0x1d759, 0x1d75a, 0x1d75b, 0x1d75c, 0x1d75d, 0x1d75e, 0x1d75f, 0x1d760, 0x1d761, 0x1d762, 0x1d763, 0x1d764, 0x1d765, 0x1d766, 0x1d767, 0x1d768, 0x1d769, 0x1d76a, 0x1d76b, 0x1d76c, 0x1d76d, 0x1d76e, 0x1d770, 0x1d771, 0x1d772, 0x1d773, 0x1d774, 0x1d775, 0x1d776, 0x1d777, 0x1d778, 0x1d779, 0x1d77a, 0x1d77b, 0x1d77c, 0x1d77d, 0x1d77e, 0x1d77f, 0x1d780, 0x1d781, 0x1d782, 0x1d783, 0x1d784, 0x1d785, 0x1d786, 0x1d787, 0x1d788, 0x1d78a, 0x1d78b, 0x1d78c, 0x1d78d, 0x1d78e, 0x1d78f, 0x1d790, 0x1d791, 0x1d792, 0x1d793, 0x1d794, 0x1d795, 0x1d796, 0x1d797, 0x1d798, 0x1d799, 0x1d79a, 0x1d79b, 0x1d79c, 0x1d79d, 0x1d79e, 0x1d79f, 0x1d7a0, 0x1d7a1, 0x1d7a2, 0x1d7a3, 0x1d7a4, 0x1d7a5, 0x1d7a6, 0x1d7a7, 0x1d7a8, 0x1d7aa, 0x1d7ab, 0x1d7ac, 0x1d7ad, 0x1d7ae, 0x1d7af, 0x1d7b0, 0x1d7b1, 0x1d7b2, 0x1d7b3, 0x1d7b4, 0x1d7b5, 0x1d7b6, 0x1d7b7, 0x1d7b8, 0x1d7b9, 0x1d7ba, 0x1d7bb, 0x1d7bc, 0x1d7bd, 0x1d7be, 0x1d7bf, 0x1d7c0, 0x1d7c1, 0x1d7c2, 0x1d7c4, 0x1d7c5, 0x1d7c6, 0x1d7c7, 0x1d7c8, 0x1d7c9, 0x1d7ca, 0x1d7cb}; } bool IsSymbolic(char c) { for (const char* ptr = symbolics; *ptr; ++ptr) if (*ptr == c) return true; return false; } // utility functions #ifdef YACAS_UINT32_T_IN_GLOBAL_NAMESPACE bool IsAlpha(uint32_t c) #else bool IsAlpha(std::uint32_t c) #endif { return c == '\'' || letters.find(c) != letters.end(); } #ifdef YACAS_UINT32_T_IN_GLOBAL_NAMESPACE bool IsAlNum(uint32_t c) #else bool IsAlNum(std::uint32_t c) #endif { return IsAlpha(c) || std::isdigit(c); } std::string LispTokenizer::NextToken(LispInput& aInput) { #ifdef YACAS_UINT32_T_IN_GLOBAL_NAMESPACE uint32_t c; #else std::uint32_t c; #endif // skip whitespaces and comments for (;;) { // End of stream: return empty string if (aInput.EndOfStream()) return ""; c = aInput.Next(); if (std::isspace(c)) continue; // parse comments if (c == '/' && aInput.Peek() == '*') { aInput.Next(); for (;;) { while (aInput.Next() != '*' && !aInput.EndOfStream()) ; if (aInput.EndOfStream()) throw LispErrCommentToEndOfFile(); if (aInput.Peek() == '/') { aInput.Next(); break; } } continue; } if (c == '/' && aInput.Peek() == '/') { aInput.Next(); while (aInput.Next() != '\n' && !aInput.EndOfStream()) ; continue; } break; } // parse brackets if (c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']') return std::string(1, c); // percent if (c == '%') return std::string(1, c); // comma and semicolon if (c == ',' || c == ';') return std::string(1, c); // parse . or .. if (c == '.' && !std::isdigit(aInput.Peek())) { std::string token; token.push_back(c); while (aInput.Peek() == '.') token.push_back(aInput.Next()); return token; } // parse literal strings if (c == '\"') { std::string str; utf8::append(c, std::back_inserter(str)); while (aInput.Peek() != '\"') { if (aInput.Peek() == '\\') { aInput.Next(); if (aInput.EndOfStream()) throw LispErrParsingInput(); switch (aInput.Next()) { case '\"': str.push_back('\"'); break; case '\\': str.push_back('\\'); break; case 't': str.push_back('\t'); break; case 'n': str.push_back('\n'); break; default: throw LispErrParsingInput(); } } else { utf8::append(aInput.Next(), std::back_inserter(str)); } if (aInput.EndOfStream()) throw LispErrParsingInput(); } utf8::append(aInput.Next(), std::back_inserter(str)); return str; } // parse atoms if (IsAlpha(c)) { std::string atom; utf8::append(c, std::back_inserter(atom)); while (IsAlNum(aInput.Peek())) utf8::append(aInput.Next(), std::back_inserter(atom)); return atom; } // parse operators if (IsSymbolic(c)) { std::string op; op.push_back(c); while (IsSymbolic(aInput.Peek())) op.push_back(aInput.Next()); return op; } // parse subscripts if (c == '_') { std::string token; utf8::append(c, std::back_inserter(token)); while (aInput.Peek() == '_') utf8::append(aInput.Next(), std::back_inserter(token)); return token; } // parse numbers if (std::isdigit(c) || c == '.') { std::string number; number.push_back(c); while (std::isdigit(aInput.Peek())) number.push_back(aInput.Next()); if (aInput.Peek() == '.') { number.push_back(aInput.Next()); while (std::isdigit(aInput.Peek())) number.push_back(aInput.Next()); } if (aInput.Peek() == 'e' || aInput.Peek() == 'E') { number.push_back(aInput.Next()); if (aInput.Peek() == '-' || aInput.Peek() == '+') number.push_back(aInput.Next()); while (std::isdigit(aInput.Peek())) number.push_back(aInput.Next()); } return number; } throw InvalidToken(); } ================================================ FILE: cyacas/libyacas/src/xmltokenizer.cpp ================================================ #include "yacas/xmltokenizer.h" #include "yacas/lisperror.h" #include #include std::string XmlTokenizer::NextToken(LispInput& aInput) { if (aInput.EndOfStream()) return ""; std::string leading_spaces; while (std::isspace(aInput.Peek())) leading_spaces.push_back(aInput.Next()); if (aInput.EndOfStream()) return ""; std::string s; char c = aInput.Next(); s.push_back(c); if (c == '<') { while (c != '>') { if (aInput.EndOfStream()) throw LispErrCommentToEndOfFile(); c = aInput.Next(); s.push_back(c); } } else { while (aInput.Peek() != '<' && !aInput.EndOfStream()) s.push_back(aInput.Next()); s = leading_spaces + s; } return s; } ================================================ FILE: cyacas/libyacas/src/yacasapi.cpp ================================================ #include "yacas/mathcommands.h" #include "yacas/standard.h" #include "yacas/yacas.h" #define OPERATOR(kind, prec, name) \ kind##operators[hash.LookUp(#name)] = LispInFixOperator(prec); DefaultYacasEnvironment::DefaultYacasEnvironment(std::ostream& os) : output(os), infixprinter( prefixoperators, infixoperators, postfixoperators, bodiedoperators), iEnvironment(coreCommands, userFunctions, globals, hash, output, infixprinter, prefixoperators, infixoperators, postfixoperators, bodiedoperators, protected_symbols, &input), input(iEnvironment.iInputStatus) { // Define the built-in functions by tying their string representation // to a kernel callable routine. #define CORE_KERNEL_FUNCTION(iname, fname, nrargs, flags) \ iEnvironment.SetCommand(fname, iname, nrargs, flags); #define CORE_KERNEL_FUNCTION_ALIAS(iname, fname, nrargs, flags) \ iEnvironment.SetCommand(fname, iname, nrargs, flags); #include "yacas/corefunctions.h" #undef CORE_KERNEL_FUNCTION #undef CORE_KERNEL_FUNCTION_ALIAS #undef OPERATOR } CYacas::CYacas(std::ostream& os) : environment(os) {} void CYacas::Evaluate(const std::string& aExpression) { LispEnvironment& env = environment.getEnv(); int stackTop = env.iStack.size(); env.iErrorOutput.clear(); env.iErrorOutput.str(""); std::ostringstream iResultOutput; LispPtr result; try { LispPtr lispexpr; // printf("Input: [%s]\n",aExpression); if (env.PrettyReader()) { const LispString* prettyReader = env.PrettyReader(); std::string full(aExpression); full.push_back(';'); StringInput input(full, env.iInputStatus); LispLocalInput localInput(env, &input); LispPtr args(nullptr); InternalApplyString(env, lispexpr, prettyReader, args); } else { LispString full(aExpression); full.push_back(';'); StringInput input(full, env.iInputStatus); env.iInputStatus.SetTo("CommandLine"); LispTokenizer& tok = *env.iCurrentTokenizer; InfixParser parser(tok, input, env, env.PreFix(), env.InFix(), env.PostFix(), env.Bodied()); parser.Parse(lispexpr); } env.iEvalDepth = 0; env.iEvaluator->ResetStack(); env.iEvaluator->Eval(env, result, lispexpr); // If no error encountered, print result if (env.PrettyPrinter()) { LispPtr nonresult; InternalApplyString(env, nonresult, env.PrettyPrinter(), result); } else { InfixPrinter infixprinter( env.PreFix(), env.InFix(), env.PostFix(), env.Bodied()); infixprinter.Print(result, iResultOutput, env); iResultOutput.put(';'); } const LispString* percent = env.HashTable().LookUp("%"); env.UnProtect(percent); env.SetVariable(percent, result, true); env.Protect(percent); } catch (const LispError& error) { HandleError(error, env, env.iErrorOutput); } env.iStack.resize(stackTop); _result = iResultOutput.str(); _error = env.iErrorOutput.str(); } ================================================ FILE: cyacas/libyacas/src/yacasnumbers.cpp ================================================ /* Implementation of the number classes (the functionality used * by yacas any way */ #include "yacas/errors.h" #include "yacas/lisperror.h" #include "yacas/numbers.h" #include "yacas/platmath.h" #include "yacas/standard.h" #include #include #include #include namespace { static LispObject* FloatToString(ANumber& aInt, LispEnvironment& aEnvironment, int aBase = 10) { std::string result; ANumberToString(result, aInt, aBase); return LispAtom::New(aEnvironment, result); } static int CalculatePrecision(const std::string& str, int aBasePrecision, int aBase, bool& aIsFloat) { const char* aString = str.c_str(); const char* ptr = aString; while (*ptr) { switch (*ptr) { case '.': goto FOUND_FLOAT_INDICATOR; case 'e': case 'E': case '@': if (aBase <= 10) goto FOUND_FLOAT_INDICATOR; break; } ptr++; } FOUND_FLOAT_INDICATOR: // decide whether the string is an integer or a float if (*ptr) { // converting to a float // estimate the number of bits we need to have // find the first significant digit: // initial zeros are not significant ptr = aString; while (*ptr == '.' || *ptr == '-' || *ptr == '0') ptr++; int digit1 = ptr - aString; // find the number of significant base digits (sig_digits) // trailing zeros and . *are* significant, do not include them in // the sets int sig_digits; // = strcspn(aString+digit1, (aBase<=10) ? "-eE@" : // "-@"); while (*ptr) { switch (*ptr) { case '@': case '-': goto FND_1; case 'e': case 'E': if (aBase <= 10) goto FND_1; } ptr++; } FND_1: sig_digits = ptr - (aString + digit1); if (sig_digits <= 0) { // this is when we have "0." in various forms // the number of digits is the number of trailing 0s after . // the string cannot consist of only 0 and -, it must contain at // least one of ".eE@" for example, -0000000.000e10 has 4 // significant digits counting . as one of the digits, so that // "0" will have 1 digit ptr = aString; while (*ptr == '-' || *ptr == '0') ptr++; sig_digits = ptr - aString; while (*ptr) { switch (*ptr) { case 'e': case 'E': case '@': goto FND_2; } ptr++; } FND_2: sig_digits = ptr - (aString + sig_digits); } else { // our number is nonzero ptr = aString + digit1; while (*ptr && *ptr != '.') ptr++; if (*ptr == '.') --sig_digits; // this is when we have "1.000001" where "." // is not a digit, so need to decrement } // ok, so we need to represent MAX(aPrecision,sig_digits) digits in // base aBase aIsFloat = true; return (int)digits_to_bits(std::max(aBasePrecision, sig_digits), aBase); } else { aIsFloat = false; return 0; } } } /* Converting between internal formats and ascii format. * It is best done as little as possible. Usually, during calculations, * the ascii version of a number will not be required, so only the * internal version needs to be stored. */ LispObject* GcdInteger(LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment) { BigNumber* i1 = int1->Number(0); BigNumber* i2 = int2->Number(0); BigNumber a(*i1); BigNumber b(*i2); if (!a.IsInt() && a.iNumber->iExp != 0) throw LispErrNotInteger(); if (!b.IsInt() && b.iNumber->iExp != 0) throw LispErrNotInteger(); a.BecomeInt(); b.BecomeInt(); BigNumber* res = new BigNumber(mp::gcd(*i1->_zz, *i2->_zz)); return new LispNumber(res); } LispObject* PowerFloat(LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment, int aPrecision) { if (int2->Number(aPrecision)->iNumber->iExp != 0) throw LispErrNotInteger(); // Raising to the power of an integer can be done fastest by squaring // and bitshifting: x^(a+b) = x^a*x^b . Then, regarding each bit // in y (seen as a binary number) as added, the algorithm becomes: // ANumber x(*int1->Number(aPrecision)->iNumber); ANumber y(*int2->Number(aPrecision)->iNumber); const bool neg = y.iNegative; y.iNegative = false; // result <- 1 ANumber result("1", aPrecision); // base <- x ANumber base(aPrecision); base.CopyFrom(x); ANumber copy(aPrecision); // while (y!=0) while (!y.IsZero()) { // if (y&1 != 0) if ((y[0] & 1) != 0) { // result <- result*base copy.CopyFrom(result); Multiply(result, copy, base); } // base <- base*base copy.CopyFrom(base); Multiply(base, copy, copy); // y <- y>>1 BaseShiftRight(y, 1); } if (neg) { ANumber one("1", aPrecision); ANumber dummy(10); copy.CopyFrom(result); Divide(result, dummy, one, copy); } // result return FloatToString(result, aEnvironment); } LispObject* ShiftLeft(LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment, int aPrecision) { BigNumber* number = new BigNumber("0", aEnvironment.BinaryPrecision()); int bits = InternalAsciiToInt(*int2->String()); number->ShiftLeft(*int1->Number(aPrecision), bits); return new LispNumber(number); } LispObject* ShiftRight(LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment, int aPrecision) { BigNumber* number = new BigNumber("0", aEnvironment.BinaryPrecision()); int bits = InternalAsciiToInt(*int2->String()); number->ShiftRight(*int1->Number(aPrecision), bits); return new LispNumber(number); } static void DivideInteger(ANumber& aQuotient, ANumber& aRemainder, const char* int1, const char* int2, int aPrecision) { ANumber a1(int1, aPrecision); ANumber a2(int2, aPrecision); if (a1.iExp != 0 || a2.iExp != 0) throw LispErrNotInteger(); if (a2.IsZero()) throw LispErrInvalidArg(); IntegerDivide(aQuotient, aRemainder, a1, a2); } LispObject* ModFloat(LispObject* int1, LispObject* int2, LispEnvironment& aEnvironment, int aPrecision) { ANumber quotient(static_cast(0)); ANumber remainder(static_cast(0)); DivideInteger(quotient, remainder, int1->String()->c_str(), int2->String()->c_str(), aPrecision); return FloatToString(remainder, aEnvironment, 10); } LispObject* LispFactorial(LispObject* int1, LispEnvironment& aEnvironment, int aPrecision) { int nr = InternalAsciiToInt(*int1->String()); if (nr < 0) throw LispErrInvalidArg(); ANumber fac("1", aPrecision); int i; for (i = 2; i <= nr; i++) BaseTimesInt(fac, i, WordBase); return FloatToString(fac, aEnvironment); } BigNumber::BigNumber(const std::string& aString, int aBasePrecision, int aBase) { bool isFloat = false; const int digits = aBasePrecision; iPrecision = CalculatePrecision(aString, aBasePrecision, aBase, isFloat); iNumber.reset(new ANumber(aString, digits, aBase)); if (!isFloat && iNumber->iExp == 0 && iNumber->iTensExp == 0) { _zz.reset(new mp::ZZ(aString, aBase)); iNumber.release(); } } BigNumber::BigNumber(const mp::ZZ& zz) : iPrecision(0), _zz(new mp::ZZ(zz)) {} BigNumber::BigNumber(const BigNumber& aOther) : iPrecision(aOther.GetPrecision()) { if (aOther.iNumber) iNumber.reset(new ANumber(*aOther.iNumber)); if (aOther._zz) _zz.reset(new mp::ZZ(*aOther._zz)); } BigNumber& BigNumber::operator=(const BigNumber& bn) { if (this == &bn) return *this; iPrecision = bn.GetPrecision(); if (bn.iNumber) { if (iNumber) iNumber->CopyFrom(*bn.iNumber); else iNumber.reset(new ANumber(*bn.iNumber)); _zz.reset(); } if (bn._zz) { if (_zz) *_zz = *bn._zz; else _zz.reset(new mp::ZZ(*bn._zz)); iNumber.reset(); } return *this; } /// Export a number to a string in given base to given base digits // FIXME API breach: aPrecision is supposed to be in digits, not bits void BigNumber::ToString(std::string& aResult, int aBasePrecision, int aBase) const { if (_zz) { aResult = _zz->to_string(aBase); return; } ANumber num(*iNumber); // TODO this round-off code is not correct yet, but will work in most cases // This is a bit of a messy way to round off numbers. It is probably // incorrect, even. When precision drops one digit, it rounds off the last // ten digits. So the following code is probably only correct if // aPrecision>=num.iPrecision or if aPrecision < num.iPrecision-10 if (aBasePrecision < num.iPrecision) { if (num.iExp > 1) num.RoundBits(); } num.ChangePrecision(aBasePrecision); if (!IsInt()) { for (;;) { const int ns = num.size(); bool greaterOne = false; if (num.iExp >= int(ns)) break; for (int i = num.iExp; i < ns; i++) { if (num[i] != 0) { if (!(i == num.iExp && num[i] < 10000 && num.iTensExp == 0)) { greaterOne = true; break; } } } if (!greaterOne) break; PlatDoubleWord carry = 0; BaseDivideInt(num, 10, WordBase, carry); num.iTensExp++; } } ANumberToString(aResult, num, aBase, !_zz); } double BigNumber::Double() const { std::string str; if (IsInt()) { str = _zz->to_string(); } else { ANumber num(*iNumber); ANumberToString(str, num, 10); } std::istringstream is(str); double d; is >> d; return d; } void BigNumber::Multiply(const BigNumber& aX, const BigNumber& aY, int aPrecision) { if (aX.IsInt() && aY.IsInt()) { BecomeInt(); *_zz = *aX._zz; *_zz *= *aY._zz; return; } if (aPrecision < aX.GetPrecision()) aPrecision = aX.GetPrecision(); if (aPrecision < aY.GetPrecision()) aPrecision = aY.GetPrecision(); BecomeFloat(bits_to_digits(aPrecision, 10)); BigNumber x(aX); x.BecomeFloat(aPrecision); BigNumber y(aY); y.BecomeFloat(aPrecision); ANumber a1(*x.iNumber); ANumber a2(*y.iNumber); ::Multiply(*iNumber, a1, a2); } void BigNumber::Add(const BigNumber& aX, const BigNumber& aY, int aPrecision) { if (aX.IsInt() && aY.IsInt()) { BecomeInt(); *_zz = *aX._zz; *_zz += *aY._zz; return; } if (aPrecision < aX.GetPrecision()) aPrecision = aX.GetPrecision(); if (aPrecision < aY.GetPrecision()) aPrecision = aY.GetPrecision(); BecomeFloat(aPrecision); BigNumber x(aX); BigNumber y(aY); x.BecomeFloat(aPrecision); y.BecomeFloat(aPrecision); ::Add(*iNumber, *x.iNumber, *y.iNumber); iNumber->SetPrecision(aPrecision); } void BigNumber::Negate(const BigNumber& aX) { if (this == &aX) { if (IsInt()) _zz->neg(); else iNumber->Negate(); return; } if (aX.IsInt()) { BecomeInt(); *_zz = *aX._zz; _zz->neg(); } else { BecomeFloat(aX.iPrecision); iNumber->CopyFrom(*aX.iNumber); iNumber->Negate(); } } void BigNumber::Divide(const BigNumber& aX, const BigNumber& aY, int aPrecision) { if (aX.IsInt() && aY.IsInt()) { if (aY._zz->is_zero()) throw LispErrInvalidArg(); BecomeInt(); _zz.reset(new mp::ZZ(*aX._zz)); *_zz /= *aY._zz; } else { int aPrecision = iPrecision; if (aPrecision < aX.GetPrecision()) aPrecision = aX.GetPrecision(); if (aPrecision < aY.GetPrecision()) aPrecision = aY.GetPrecision(); int digitPrecision = bits_to_digits(aPrecision, 10); BecomeFloat(aPrecision); BigNumber x(aX); x.BecomeFloat(digitPrecision); BigNumber y(aY); y.BecomeFloat(digitPrecision); iPrecision = aPrecision; iNumber->iPrecision = digitPrecision; ANumber a1(*x.iNumber); a1.ChangePrecision(digitPrecision); ANumber a2(*y.iNumber); a2.ChangePrecision(digitPrecision); ANumber remainder(digitPrecision); if (a2.IsZero()) throw LispErrInvalidArg(); ::Divide(*iNumber, remainder, a1, a2); } } void BigNumber::ShiftLeft(const BigNumber& aX, int aNrToShift) { if (this != &aX) *this = aX; BecomeInt(); *_zz <<= aNrToShift; } void BigNumber::ShiftRight(const BigNumber& aX, int aNrToShift) { if (this != &aX) *this = aX; BecomeInt(); *_zz >>= aNrToShift; } void BigNumber::BitAnd(const BigNumber& aX, const BigNumber& aY) { BecomeInt(); BigNumber x(aX); x.BecomeInt(); BigNumber y(aY); y.BecomeInt(); *_zz = *x._zz; *_zz &= *y._zz; } void BigNumber::BitOr(const BigNumber& aX, const BigNumber& aY) { BecomeInt(); BigNumber x(aX); x.BecomeInt(); BigNumber y(aY); y.BecomeInt(); *_zz = *x._zz; *_zz |= *y._zz; _zz->abs(); } void BigNumber::BitXor(const BigNumber& aX, const BigNumber& aY) { BecomeInt(); BigNumber x(aX); x.BecomeInt(); BigNumber y(aY); y.BecomeInt(); *_zz = *x._zz; *_zz ^= *y._zz; _zz->abs(); } void BigNumber::BitNot(const BigNumber& aX) { BecomeInt(); BigNumber x(aX); x.BecomeInt(); *_zz = *x._zz; _zz->neg(); _zz->abs(); } /// Bit count operation: return the number of significant bits if integer, /// return the binary exponent if float (shortcut for binary logarithm) // give BitCount as platform integer signed long BigNumber::BitCount() const { if (_zz) { if (_zz->is_zero()) return 0; return _zz->no_bits(); } if (iNumber->IsZero()) return 0; //-(1L<<30); ANumber num(*iNumber); if (num.iTensExp < 0) { int digs = WordDigits(num.iPrecision, 10); PlatWord zero = 0; while (num.iExp < digs) { num.insert(num.begin(), zero); num.iExp++; } } while (num.iTensExp < 0) { PlatDoubleWord carry = 0; BaseDivideInt(num, 10, WordBase, carry); num.iTensExp++; } while (num.iTensExp > 0) { BaseTimesInt(num, 10, WordBase); num.iTensExp--; } int i, nr = num.size(); for (i = nr - 1; i >= 0; i--) if (num[i] != 0) break; int bits = (i - num.iExp) * sizeof(PlatWord) * 8; if (i >= 0) { PlatWord w = num[i]; while (w) { w >>= 1; bits++; } } return (bits); } int BigNumber::Sign() const { if (IsInt()) { if (_zz->is_negative()) return -1; if (_zz->is_zero()) return 0; return 1; } if (iNumber->iNegative) return -1; if (iNumber->IsZero()) return 0; return 1; } void BigNumber::DumpDebugInfo(std::ostream& os) const { if (!iNumber) os << "No number representation\n"; else iNumber->Print(os, "Number:"); } void BigNumber::Floor(const BigNumber& aX) { if (aX.IsInt()) { BecomeInt(); *_zz = *aX._zz; return; } iNumber->CopyFrom(*aX.iNumber); // If iExp is zero, then we can not look at the decimals and determine the // floor. // This number has to have digits (see code later in this routine that does // a division). Not extending the digits caused the MathFloor function to // fail on n*10-m where n was an integer. The code below divides away the // 10^-m, but since iExp was zero, this resulted in a premature truncation // (seen when n<0) if (iNumber->iExp == 0) iNumber->ChangePrecision(iNumber->iPrecision); if (iNumber->iExp > 1) iNumber->RoundBits(); // TODO FIXME slow code! But correct if (iNumber->iTensExp > 0) { while (iNumber->iTensExp > 0) { BaseTimesInt(*iNumber, 10, WordBase); iNumber->iTensExp--; } } else if (iNumber->iTensExp < 0) { while (iNumber->iTensExp < 0) { PlatDoubleWord carry; BaseDivideInt(*iNumber, 10, WordBase, carry); iNumber->iTensExp++; } } iNumber->ChangePrecision(iNumber->iPrecision); int i = 0; int fraciszero = true; while (i < iNumber->iExp && fraciszero) { PlatWord digit = (*iNumber)[i]; if (digit != 0) fraciszero = false; i++; } iNumber->erase(iNumber->begin(), iNumber->begin() + iNumber->iExp); iNumber->iExp = 0; if (iNumber->iNegative && !fraciszero) { ANumber orig(*iNumber); ANumber minone("-1", 10); ::Add(*iNumber, orig, minone); } BecomeInt(); } void BigNumber::Precision(int aPrecision) { // FIXME if (aPrecision < 0) aPrecision = 0; if (iNumber && aPrecision > iPrecision) iNumber->ChangePrecision(bits_to_digits(aPrecision, 10)); iPrecision = aPrecision; } // basic object manipulation bool BigNumber::Equals(const BigNumber& aOther) const { if (IsInt() && aOther.IsInt()) return *_zz == *aOther._zz; if (aOther.IsInt() && aOther._zz->is_zero()) { BigNumber x(*this); std::string s; x.ToString(s, iPrecision); } if (IsInt() && _zz->is_zero()) { BigNumber x(aOther); std::string s; x.ToString(s, iPrecision); } BigNumber x(*this); BigNumber y(aOther); int precision = std::max(x.iPrecision, y.iPrecision); x.BecomeFloat(precision); y.BecomeFloat(precision); if (x.iNumber->iExp == y.iNumber->iExp) { x.iNumber->DropTrailZeroes(); y.iNumber->DropTrailZeroes(); if (x.iNumber->IsZero()) x.iNumber->iNegative = false; if (y.iNumber->IsZero()) y.iNumber->iNegative = false; if (x.iNumber->ExactlyEqual(*y.iNumber)) return true; if (IsInt()) return false; if (aOther.Sign() != Sign()) return false; } { // TODO optimize!!!! /*For tiny numbers like 1e-600, the following seemed necessary to compare it with zero. if (precision< (35*-iNumber->iTensExp)/10) precision = (35*-iNumber->iTensExp)/10; if (precision< (35*-aOther.iNumber->iTensExp)/10) precision = (35*-aOther.iNumber->iTensExp)/10; */ BigNumber diff("0", precision); BigNumber otherNeg(aOther); otherNeg.Negate(aOther); diff.Add(*this, otherNeg, bits_to_digits(precision, 10)); // if the numbers are float, make sure they are normalized if (diff.iNumber->iExp || diff.iNumber->iTensExp) { int pr = diff.iNumber->iPrecision; if (pr < iPrecision) pr = iPrecision; if (pr < aOther.iPrecision) pr = aOther.iPrecision; NormalizeFloat(*diff.iNumber, WordDigits(pr, 10)); } return !Significant(*diff.iNumber); } } bool BigNumber::IsInt() const { return !!_zz; } bool BigNumber::IsSmall() const { if (IsInt()) { return _zz->no_bits() <= 53; // PlatWord* ptr = &((*iNumber)[iNumber->size() - 1]); // int nr = iNumber->size(); // while (nr > 1 && *ptr == 0) { // ptr--; // nr--; // } // return (nr <= iNumber->iExp + 1); } else // a function to test smallness of a float is not present in ANumber, need // to code a workaround to determine whether a number fits into double. { int tensExp = iNumber->iTensExp; if (tensExp < 0) tensExp = -tensExp; return (iNumber->iPrecision <= 53 // standard float is 53 bits && tensExp < 1021 // 306 // 1021 bits is about 306 decimals ); // standard range of double precision is about 53 bits of mantissa and // binary exponent of about 1021 } } void BigNumber::BecomeInt() { if (IsInt()) return; while (iNumber->iTensExp > 0) { BaseTimesInt(*iNumber, 10, WordBase); iNumber->iTensExp--; } while (iNumber->iTensExp < 0) { PlatDoubleWord carry = 0; BaseDivideInt(*iNumber, 10, WordBase, carry); iNumber->iTensExp++; } iNumber->ChangePrecision(0); ANumber a = *iNumber; std::string s; ANumberToString(s, a, 10, false); _zz.reset(new mp::ZZ(s)); iNumber.release(); } /// Transform integer to float, setting a given bit precision. /// Note that aPrecision=0 means automatic setting (just enough digits to /// represent the integer). void BigNumber::BecomeFloat(int aPrecision) { // FIXME: need to specify precision explicitly if (!IsInt()) return; const int precision = std::max(iPrecision, aPrecision); iNumber.reset(new ANumber( _zz->to_string(), bits_to_digits(precision, 10))); // is this OK or ChangePrecision means // floating-point precision? _zz.release(); } bool BigNumber::LessThan(const BigNumber& aOther) const { if (IsInt() && aOther.IsInt()) return *_zz < *aOther._zz; BigNumber x(*this); BigNumber y(aOther); const int precision = std::max(x.iPrecision, y.iPrecision); x.BecomeFloat(precision); y.BecomeFloat(precision); ANumber a1(*x.iNumber); ANumber a2(*y.iNumber); return ::LessThan(a1, a2); } ================================================ FILE: cyacas/libyacas_mp/CMakeLists.txt ================================================ # # # This file is part of yacas. # Yacas is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesset General Public License as # published by the Free Software Foundation, either version 2.1 # of the License, or (at your option) any later version. # # Yacas is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with yacas. If not, see . # # set (SOURCES src/limbs_vector.cpp src/nn.cpp src/zz.cpp src/rr.cpp) set (HEADERS include/yacas/mp/limbs_vector.hpp include/yacas/mp/nn.hpp include/yacas/mp/zz.hpp include/yacas/mp/rr.hpp) add_library (libyacas_mp ${SOURCES} ${HEADERS}) set_target_properties (libyacas_mp PROPERTIES OUTPUT_NAME "yacas_mp" INTERPROCEDURAL_OPTIMIZATION ${IPO_SUPPORTED}) target_include_directories (libyacas_mp PUBLIC include) target_link_libraries(libyacas_mp PUBLIC coverage_config) install (TARGETS libyacas_mp LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT app) install (DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT dev) # if (APPLE) # add_library (libyacas_mp_framework SHARED ${SOURCES} ${HEADERS}) # set_target_properties(libyacas_mp_framework PROPERTIES OUTPUT_NAME "yacas_mp" VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION} FRAMEWORK ON) # target_include_directories (libyacas_mp_framework PUBLIC include) # add_custom_command(TARGET libyacas_mp_framework POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/include $/Headers) # add_custom_command(TARGET libyacas_mp_framework POST_BUILD COMMAND cd "$/../.." && rm -f Headers && ln -s Versions/Current/Headers Headers) # install (TARGETS libyacas_mp_framework FRAMEWORK DESTINATION ${CMAKE_INSTALL_FRAMEWORK_PREFIX} COMPONENT framework) # endif() if (ENABLE_CYACAS_BENCHMARKS) add_subdirectory (benchmark) endif () if (ENABLE_CYACAS_UNIT_TESTS) add_subdirectory (test) endif () ================================================ FILE: cyacas/libyacas_mp/benchmark/CMakeLists.txt ================================================ # # # This file is part of yacas. # Yacas is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesset General Public License as # published by the Free Software Foundation, either version 2.1 # of the License, or (at your option) any later version. # # Yacas is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with yacas. If not, see . # # find_package (Threads REQUIRED) find_package (benchmark REQUIRED) add_executable (yacas_mp_nn_benchmark src/nn_benchmark.cpp) target_link_libraries (yacas_mp_nn_benchmark libyacas_mp benchmark::benchmark benchmark::benchmark_main Threads::Threads) add_custom_target(bench COMMAND yacas_mp_nn_benchmark --benchmark_min_time=0.1) ================================================ FILE: cyacas/libyacas_mp/benchmark/src/nn_benchmark.cpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesset General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ #include "yacas/mp/nn.hpp" #include #include std::mt19937_64 rng; using namespace yacas::mp; std::string random_string(std::size_t length) { auto randchar = []() -> char { const char charset[] = "0123456789"; const size_t max_index = (sizeof(charset) - 1); return charset[rand() % max_index]; }; std::string str(length, 0); std::generate_n(str.begin(), length, randchar); return str; } static void BM_NN_construct_random(benchmark::State& state) { for (auto _: state) { NN b(state.range(), rng); } state.SetComplexityN(state.range()); } static void BM_NN_parse(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); const std::string s = random_string(state.range()); state.ResumeTiming(); NN b(s); } state.SetComplexityN(state.range()); } static void BM_NN_to_string(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); NN a(state.range(0), rng); state.ResumeTiming(); a.to_string(10); } state.SetComplexityN(state.range()); } static void BM_NN_shift_left(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); NN a(state.range(0), rng); state.ResumeTiming(); a <<= state.range(1); } state.SetComplexityN(state.range(0)); } static void BM_NN_add(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); NN a(state.range(0), rng); NN b(state.range(1), rng); state.ResumeTiming(); a += b; } state.SetComplexityN(std::min(state.range(0), state.range(1))); } static void BM_NN_add_self(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); NN a(state.range(0), rng); state.ResumeTiming(); a += a; } state.SetComplexityN(state.range()); } static void BM_NN_add_same(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); NN a(random_string(state.range(0))); NN b(random_string(state.range(0))); state.ResumeTiming(); a += b; } state.SetComplexityN(state.range()); } static void BM_NN_sqr(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); NN a(random_string(state.range(0))); state.ResumeTiming(); a.sqr(); } state.SetComplexityN(state.range()); } static void BM_NN_mul_same(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); NN a(random_string(state.range(0))); NN b(random_string(state.range(0))); state.ResumeTiming(); a *= b; } state.SetComplexityN(state.range()); } static void BM_NN_mul(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); NN a(random_string(state.range(0))); NN b(random_string(state.range(1))); state.ResumeTiming(); a *= b; } state.SetComplexityN(state.range(0) * state.range(1)); } static void BM_NN_div(benchmark::State& state) { for (auto _: state) { state.PauseTiming(); NN a(random_string(state.range(0))); NN b(random_string(state.range(1))); if (b.is_zero()) b = NN::ONE; state.ResumeTiming(); a /= b; } state.SetComplexityN(state.range(0)); } BENCHMARK(BM_NN_construct_random)->Range(1, 1<<16)->Complexity(); BENCHMARK(BM_NN_parse)->Range(1, 1<<14)->Complexity(); BENCHMARK(BM_NN_to_string)->Range(1, 1 << 16); BENCHMARK(BM_NN_shift_left)->Ranges({{1, 1<<8}, {1, 1<<8}}); BENCHMARK(BM_NN_add)->Ranges({{1, 1<<8}, {1, 1<<8}}); BENCHMARK(BM_NN_add_self)->Range(1, 16); BENCHMARK(BM_NN_add_self)->Range(16, 1<<10); BENCHMARK(BM_NN_add_same)->Range(1, 16); BENCHMARK(BM_NN_add_same)->Range(16, 1<<10); BENCHMARK(BM_NN_sqr)->Range(1, 1<<16); BENCHMARK(BM_NN_mul_same)->Range(1, 16); BENCHMARK(BM_NN_mul_same)->Range(16, 1<<10); BENCHMARK(BM_NN_mul)->Ranges({{1, 1<<8}, {1, 1<<8}}); BENCHMARK(BM_NN_div)->Ranges({{1, 1<<8}, {1, 1<<8}}); BENCHMARK_MAIN(); ================================================ FILE: cyacas/libyacas_mp/include/yacas/mp/limbs_vector.hpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ #ifndef YACAS_MP_LIMBS_VECTOR_HPP #define YACAS_MP_LIMBS_VECTOR_HPP #include #include #include #include #include namespace yacas::mp { /// @brief A vector of limbs. /// @details This class is a simple vector of limbs. It is used to store the /// limbs of a multi-precision integer. It is implemented as a small buffer /// optimization. If the number of limbs is less than or equal to 2, the /// limbs are stored in a std::array. Otherwise, the limbs are stored in a /// std::unique_ptr. This allows the class to avoid dynamic memory /// allocation for small numbers of limbs. The class provides a simple /// interface for manipulating the limbs, including iterators, push_back, /// pop_back, and resizing. The class also provides a swap method for /// efficiently swapping the contents of two LimbsVector objects. The class /// is also comparable and hashable. class LimbsVector { public: typedef std::uint32_t Limb; typedef std::uint64_t Limb2; typedef Limb value_type; typedef std::uint32_t size_type; typedef std::int32_t difference_type; typedef value_type* iterator; typedef const value_type* const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; /// @brief Default constructor. /// @details Constructs an empty LimbsVector. LimbsVector() noexcept; /// @brief Constructor from an initializer list. /// @details Constructs a LimbsVector from an initializer list of limbs. LimbsVector(const std::initializer_list& limbs); /// @brief Constructor from a size and a value. /// @details Constructs a LimbsVector of a given size, with all limbs /// initialized to a given value. LimbsVector(std::size_t n, Limb value); /// @brief Copy constructor. /// @details Constructs a LimbsVector from another LimbsVector. explicit LimbsVector(const LimbsVector& limbs); /// @brief Move constructor. /// @details Constructs a LimbsVector by moving the contents of another /// LimbsVector. explicit LimbsVector(LimbsVector&& limbs) noexcept; /// @brief Constructor from a range. /// @details Constructs a LimbsVector from a range of limbs. template explicit LimbsVector(const Container& container) { for (const auto& limb : container) push_back(limb); } /// @brief Destructor. ~LimbsVector() = default; /// @brief Comparison operator. /// @details Compares two LimbsVector objects for ordering. The /// comparison is lexicographical, with the most significant limb /// compared first. std::strong_ordering operator<=>(const LimbsVector& that) const noexcept; /// @brief Equality comparison. /// @details Compares two LimbsVector objects for equality. bool operator==(const LimbsVector& that) const noexcept; /// @brief Inequality comparison. /// @details Compares two LimbsVector objects for inequality. bool operator!=(const LimbsVector& that) const noexcept; /// @brief Assignment operator. /// @details Assigns the contents of another LimbsVector to this one. LimbsVector& operator=(const LimbsVector& other); /// @brief Move assignment operator. /// @details Moves the contents of another LimbsVector to this one. LimbsVector& operator=(LimbsVector&& other) noexcept; template void assign(InputIterator b, InputIterator e) { clear(); for (auto it = b; it != e; ++it) push_back(*it); } /// @brief Swaps the contents of two LimbsVector objects. /// @details Swaps the contents of two LimbsVector objects in constant /// time. void swap(LimbsVector& other) noexcept; /// @brief Inserts a value at a given position. /// @details Inserts n copies of a value at a given position in the void insert(iterator b, std::size_t n, Limb value); /// @brief Erases a range of values. /// @details Erases a range of values from the LimbsVector. void erase(iterator b, iterator e); /// @brief Returns an iterator to the beginning of the LimbsVector. iterator begin() noexcept; /// @brief Returns an iterator to the end of the LimbsVector. iterator end() noexcept; /// @brief Returns a const iterator to the beginning of the LimbsVector. const_iterator begin() const noexcept; /// @brief Returns a const iterator to the end of the LimbsVector. const_iterator end() const noexcept; /// @brief Returns a const iterator to the beginning of the LimbsVector. const_iterator cbegin() const; /// @brief Returns a const iterator to the end of the LimbsVector. const_iterator cend() const; /// @brief Returns a reverse iterator to the beginning of the /// LimbsVector. reverse_iterator rbegin(); /// @brief Returns a reverse iterator to the end of the LimbsVector. reverse_iterator rend(); /// @brief Returns a const reverse iterator to the beginning of the /// LimbsVector. const_reverse_iterator crbegin() const; /// @brief Returns a const reverse iterator to the end of the /// LimbsVector. const_reverse_iterator crend() const; /// @brief Clears the LimbsVector. /// @details Removes all limbs from the LimbsVector. void clear(); /// @brief Returns the number of limbs in the LimbsVector. std::size_t size() const noexcept; /// @brief Returns true if the vector is empty, false otherwise. bool empty() const noexcept; /// @brief Appends a limb to the end of the LimbsVector. void push_back(Limb limb); /// @brief Removes the last limb from the LimbsVector. void pop_back(); /// @brief Resizes the LimbsVector. /// @details Resizes the LimbsVector to a given size. If the new size is /// greater than the current size, the new limbs are initialized to a /// given value. If the new size is less than the current size, the /// extra limbs are removed. void resize(std::size_t n, Limb value = 0); /// @brief Reserves space for a given number of limbs. /// @details Reserves space for a given number of limbs. If the new /// capacity is greater than the current capacity, the capacity is /// increased. If the new capacity is less than the current capacity, /// the capacity is decreased. void reserve(std::size_t new_capacity); /// @brief Returns a pointer to the underlying data. Limb* data(); /// @brief Returns a pointer to the underlying data. const Limb* data() const; /// @brief Returns a reference to the limb at a given index. /// @details Returns a reference to the limb at a given index. The index /// must be less than the size of the LimbsVector. Limb& operator[](std::size_t index); const Limb& operator[](std::size_t index) const; /// @brief Returns a reference to the first limb. /// @details Returns a reference to the first limb in the LimbsVector. /// The LimbsVector must not be empty. Limb& front(); /// @brief Returns a const reference to the first limb. /// @details Returns a const reference to the first limb in the /// LimbsVector. The LimbsVector must not be empty. const Limb& front() const; /// @brief Returns a reference to the last limb. /// @details Returns a reference to the last limb in the LimbsVector. /// The LimbsVector must not be empty. Limb& back(); /// @brief Returns a const reference to the last limb. /// @details Returns a const reference to the last limb in the /// LimbsVector. The LimbsVector must not be empty. const Limb& back() const; private: std::variant, std::unique_ptr> m_data; std::size_t m_size; std::size_t m_capacity; void _grow(std::size_t new_capacity); }; } #endif ================================================ FILE: cyacas/libyacas_mp/include/yacas/mp/nn.hpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesset General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ #ifndef YACAS_MP_NN_HPP #define YACAS_MP_NN_HPP #include #include #include #include #include #include #include #include #include #include "limbs_vector.hpp" namespace yacas { namespace mp { class NN { public: typedef std::uint32_t Limb; typedef std::uint64_t Limb2; static const NN ZERO; static const NN ONE; static const NN TWO; static const NN TEN; static unsigned PARSE_DC_THRESHOLD; static unsigned TO_STRING_DC_THRESHOLD; static unsigned DIV_REM_DC_THRESHOLD; static unsigned MUL_TOOM22_THRESHOLD; static unsigned MUL_TOOM33_THRESHOLD; struct ParseError : public std::invalid_argument { ParseError(std::string_view s, std::size_t) : std::invalid_argument("yacas::mp::NN: error parsing " + std::string(s)) { } }; struct DivisionByZeroError : public std::domain_error { explicit DivisionByZeroError(std::string_view s) : std::domain_error("yacas::mp::NN: attempt to divide " + std::string(s) + " by zero") { } }; NN() = default; explicit NN(Limb); /// @brief Construct from a vector of limbs. explicit NN(const std::vector&); /// @brief Construct from a string. /// @param s The string to parse. /// @param b The base of the number. /// @throw ParseError if the string cannot be parsed. explicit NN(std::string_view, unsigned b = 10); /// @brief Construct a random number with a given number of bits. template NN(unsigned no_bits, RndEngine& engine); bool operator==(Limb) const noexcept; bool operator!=(Limb) const noexcept; std::strong_ordering operator<=>(Limb) const noexcept; /// @brief Equality comparison. bool operator==(const NN&) const noexcept = default; /// @brief Ordering comparison. std::strong_ordering operator<=>(const NN&) const noexcept; NN& operator+=(Limb); NN& operator-=(Limb); NN& operator*=(Limb); NN& operator/=(Limb); NN& operator%=(Limb); NN& operator+=(const NN&); NN& operator-=(const NN&); NN& operator*=(const NN&); NN& operator/=(const NN&); NN& operator%=(const NN&); NN& operator<<=(unsigned); NN& operator>>=(unsigned); NN& operator|=(const NN&); NN& operator&=(const NN&); NN& operator^=(const NN&); bool is_zero() const; bool is_even() const; void clear(); unsigned to_unsigned() const; /// @brief Return the number as a string. std::string to_string(unsigned base = 10) const; void sqr(); void pow(unsigned); /// @brief Return the number of bits. unsigned long no_bits() const; /// @brief Return the number of decimal digits. unsigned long no_digits() const; /// @brief Test a bit. bool test(unsigned long bit) const; /// @brief Set a bit. void set(unsigned long bit); /// @brief Clear a bit. void clear(unsigned long bit); /// @brief Return the limbs. const LimbsVector& limbs() const; private: static constexpr int LIMB_BITS = sizeof(Limb) * CHAR_BIT; static constexpr int LIMB2_BITS = sizeof(Limb2) * CHAR_BIT; static constexpr Limb LIMB_MAX = std::numeric_limits::max(); static constexpr Limb2 BASE = static_cast(LIMB_MAX) + 1; LimbsVector _limbs; template NN(Iter b, Iter e) { std::copy(b, e, std::back_inserter(_limbs)); drop_zeros(); } void drop_zeros(); void add(Limb); void sub(Limb); void mul(Limb); void div(Limb); void rem(Limb); Limb div_rem(Limb); void shift_left(unsigned n); void shift_right(unsigned n); void add(const NN&, unsigned shift = 0); void sub(const NN&, unsigned shift = 0); void mul(const NN&); void div(const NN&); void rem(const NN&); NN div_rem(const NN&); void sqr_bc(); void sqr_toom22(); void sqr_toom33(); void mul_bc(const NN&); void mul_toom22(const NN&); void mul_toom33(const NN&); NN div_rem_bc(const NN&); std::string to_string_bc(unsigned base = 10) const; std::string to_string_dc(unsigned base = 10) const; }; NN gcd(NN a, NN b); inline NN::NN(Limb n) { if (n != 0) _limbs.push_back(n); } inline NN::NN(const std::vector& limbs) : _limbs(limbs) { drop_zeros(); } template NN::NN(unsigned no_bits, RndEngine& engine) { const unsigned no_limbs = ((unsigned long)no_bits + LIMB_BITS - 1) / LIMB_BITS; const unsigned no_full_limbs = no_bits / LIMB_BITS; _limbs.reserve(no_limbs); std::uniform_int_distribution distribution; for (unsigned i = 0; i < no_full_limbs; ++i) _limbs.push_back(distribution(engine)); const unsigned excess_bits = no_limbs * LIMB_BITS - no_bits; if (excess_bits) { distribution = std::uniform_int_distribution( 0, static_cast(1) << (excess_bits - 1)); _limbs.push_back(distribution(engine)); } drop_zeros(); } inline bool NN::operator==(Limb n) const noexcept { return _limbs.size() == 1 && _limbs.front() == n; } inline bool NN::operator!=(Limb n) const noexcept { return !(*this == n); } inline std::strong_ordering NN::operator<=>(Limb n) const noexcept { if (_limbs.size() == 1) { if (_limbs.front() < n) return std::strong_ordering::less; if (_limbs.front() > n) return std::strong_ordering::greater; return std::strong_ordering::equal; } if (_limbs.empty()) { if (n == 0) return std::strong_ordering::equal; else return std::strong_ordering::less; } return std::strong_ordering::greater; } inline std::strong_ordering NN::operator<=>(const NN& n) const noexcept { if (_limbs.size() < n._limbs.size()) return std::strong_ordering::less; if (_limbs.size() > n._limbs.size()) return std::strong_ordering::greater; return std::lexicographical_compare_three_way(_limbs.crbegin(), _limbs.crend(), n._limbs.crbegin(), n._limbs.crend()); } inline NN& NN::operator+=(Limb n) { add(n); return *this; } inline NN& NN::operator-=(Limb n) { sub(n); return *this; } inline NN& NN::operator*=(Limb n) { mul(n); return *this; } inline NN& NN::operator/=(Limb n) { div_rem(n); return *this; } inline NN& NN::operator%=(Limb n) { _limbs = {div_rem(n)}; drop_zeros(); return *this; } inline NN& NN::operator+=(const NN& n) { add(n); return *this; } inline NN& NN::operator-=(const NN& n) { sub(n); return *this; } inline NN& NN::operator*=(const NN& n) { mul(n); return *this; } inline NN& NN::operator/=(const NN& n) { div(n); return *this; } inline NN& NN::operator%=(const NN& n) { rem(n); return *this; } inline NN& NN::operator<<=(unsigned n) { shift_left(n); return *this; } inline NN& NN::operator>>=(unsigned n) { shift_right(n); return *this; } inline NN& NN::operator|=(const NN& b) { const unsigned n = static_cast(b._limbs.size()); if (_limbs.size() < n) _limbs.resize(n, 0); Limb* __restrict p = _limbs.data(); const Limb* __restrict q = b._limbs.data(); for (unsigned i = 0; i < n; ++i) *p++ |= *q++; return *this; } inline NN& NN::operator&=(const NN& b) { const unsigned n = static_cast(b._limbs.size()); if (_limbs.size() > n) _limbs.resize(n); const unsigned m = static_cast(_limbs.size()); Limb* __restrict p = _limbs.data(); const Limb* __restrict q = b._limbs.data(); for (unsigned i = 0; i < m; ++i) *p++ &= *q++; drop_zeros(); return *this; } inline NN& NN::operator^=(const NN& b) { const unsigned n = static_cast(b._limbs.size()); if (_limbs.size() > n) _limbs.resize(n); const unsigned m = static_cast(_limbs.size()); Limb* __restrict p = _limbs.data(); const Limb* __restrict q = b._limbs.data(); for (unsigned i = 0; i < m; ++i) *p++ ^= *q++; drop_zeros(); return *this; } inline unsigned long NN::no_bits() const { if (is_zero()) return 1; #ifdef _MSC_VER unsigned long index = 0; _BitScanReverse(&index, _limbs.back()); return static_cast(_limbs.size() * LIMB_BITS - (31 - index)); #else return static_cast(_limbs.size() * LIMB_BITS - __builtin_clz(_limbs.back())); #endif } inline unsigned long NN::no_digits() const { if (is_zero()) return 1; const unsigned n = ((no_bits() + 1) * 646456993) >> 31; NN t = TEN; t.pow(n); return *this < t ? n : n + 1; } inline bool NN::test(unsigned long bit) const { assert(bit < _limbs.size() * LIMB_BITS); return _limbs[bit / LIMB_BITS] & (1 << (bit % LIMB_BITS)); } inline void NN::set(unsigned long bit) { assert(bit < _limbs.size() * LIMB_BITS); _limbs[bit / LIMB_BITS] |= (1 << (bit % LIMB_BITS)); } inline void NN::clear(unsigned long bit) { assert(bit < _limbs.size() * LIMB_BITS); _limbs[bit / LIMB_BITS] &= ~(1 << (bit % LIMB_BITS)); } inline bool NN::is_zero() const { return _limbs.empty(); } inline bool NN::is_even() const { if (is_zero()) return true; return !(_limbs.front() & 1); } inline void NN::clear() { _limbs.clear(); } inline unsigned NN::to_unsigned() const { if (is_zero()) return 0; return _limbs.front(); } inline void NN::drop_zeros() { while (!_limbs.empty() && (_limbs.back() == 0)) _limbs.pop_back(); } inline const LimbsVector& NN::limbs() const { return _limbs; } inline ::std::ostream& operator<<(::std::ostream& os, const NN& n) { unsigned base = 10; if (os.flags() & std::ios::hex) base = 16; if (os.flags() & std::ios::oct) base = 8; return os << n.to_string(base); } inline ::std::istream& operator>>(::std::istream& os, NN& n) { unsigned base = 10; if (os.flags() & std::ios::hex) base = 16; if (os.flags() & std::ios::oct) base = 8; std::string s; os >> s; n = NN(s, base); return os; } } } #endif ================================================ FILE: cyacas/libyacas_mp/include/yacas/mp/rr.hpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesset General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ #ifndef YACAS_MP_RR_HPP #define YACAS_MP_RR_HPP #endif ================================================ FILE: cyacas/libyacas_mp/include/yacas/mp/zz.hpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ #ifndef YACAS_MP_ZZ_HPP #define YACAS_MP_ZZ_HPP #include "nn.hpp" namespace yacas { namespace mp { class ZZ { public: static const ZZ ZERO; static const ZZ ONE; static const ZZ TWO; static const ZZ TEN; struct ParseError : public std::invalid_argument { ParseError(std::string_view s, std::size_t) : std::invalid_argument("yacas::mp::ZZ: error parsing " + std::string(s)) { } }; struct DivisionByZeroError : public std::domain_error { explicit DivisionByZeroError(std::string_view s) : std::domain_error("yacas::mp::ZZ: attempt to divide " + std::string(s) + " by zero") { } }; ZZ(); explicit ZZ(int); explicit ZZ(const NN&); explicit ZZ(std::string_view s, unsigned b = 10); template ZZ(unsigned no_bits, RndEngine& engine); bool operator==(int) const; bool operator!=(int) const; std::strong_ordering operator<=>(int) const noexcept; bool operator==(const ZZ&) const noexcept = default; /// @brief Ordering comparison. std::strong_ordering operator<=>(const ZZ&) const noexcept; ZZ& operator+=(int); ZZ& operator-=(int); ZZ& operator*=(int); ZZ& operator/=(int); ZZ& operator%=(int); ZZ& operator+=(const ZZ&); ZZ& operator-=(const ZZ&); ZZ& operator*=(const ZZ&); ZZ& operator/=(const ZZ&); ZZ& operator%=(const ZZ&); ZZ& operator<<=(unsigned); ZZ& operator>>=(unsigned); ZZ& operator|=(const ZZ&); ZZ& operator&=(const ZZ&); ZZ& operator^=(const ZZ&); bool is_zero() const; bool is_positive() const; bool is_negative() const; bool is_even() const; void clear(); const NN& to_NN() const; int to_int() const; std::string to_string(unsigned base = 10) const; void abs(); void neg(); void sqr(); void pow(unsigned); unsigned long no_bits() const; unsigned long no_digits() const; bool test(unsigned long bit) const; void set(unsigned long bit); void clear(unsigned long bit); private: NN _nn; bool _neg; }; inline ZZ gcd(ZZ a, ZZ b) { a.abs(); b.abs(); return ZZ(gcd(a.to_NN(), b.to_NN())); } inline ZZ::ZZ() : _neg(false) {} inline ZZ::ZZ(int i) : _nn(std::abs(i)), _neg(i < 0) {} inline ZZ::ZZ(const NN& n) : _nn(n), _neg(false) {} template ZZ::ZZ(unsigned no_bits, RndEngine& engine) : _nn(no_bits, engine), _neg(false) { } inline bool ZZ::operator==(int i) const { if (_neg == (i < 0)) return _nn == std::abs(i); return false; } inline bool ZZ::operator!=(int i) const { return !(*this == i); } inline std::strong_ordering ZZ::operator<=>(const ZZ& z) const noexcept { if (_neg && !z._neg) return std::strong_ordering::less; if (!_neg && z._neg) return std::strong_ordering::greater; if (_neg && z._neg) return z._nn <=> _nn; return _nn <=> z._nn; } inline ZZ& ZZ::operator+=(int i) { if (i == 0) return *this; if (_neg == (i < 0)) { _nn += std::abs(i); return *this; } i = std::abs(i); if (_nn > i) { _nn -= i; } else { NN t(i); t -= _nn; _nn = std::move(t); if (_nn.is_zero()) _neg = false; else _neg = !_neg; } return *this; } inline ZZ& ZZ::operator-=(int i) { *this += -i; return *this; } inline ZZ& ZZ::operator*=(int i) { if (i == 0) { clear(); return *this; } if (i < 0) { _neg = !_neg; i = -i; } _nn *= i; return *this; } inline ZZ& ZZ::operator/=(int i) { if (i == 0) throw DivisionByZeroError(to_string()); if (i < 0) { _neg = !_neg; i = -i; } _nn /= i; if (_nn.is_zero()) _neg = false; return *this; } inline ZZ& ZZ::operator%=(int i) { if (i == 0) throw DivisionByZeroError(to_string()); if (i < 0) { _neg = !_neg; i = -i; } _nn %= i; if (_nn.is_zero()) _neg = false; return *this; } inline ZZ& ZZ::operator+=(const ZZ& z) { if (_neg == z._neg) { _nn += z._nn; return *this; } if (_nn > z._nn) { _nn -= z._nn; } else { NN t(z._nn); t -= _nn; _nn = std::move(t); if (_nn.is_zero()) _neg = false; else _neg = !_neg; } return *this; } inline ZZ& ZZ::operator-=(const ZZ& z) { if (_neg != z._neg) { _nn += z._nn; return *this; } if (_nn > z._nn) { _nn -= z._nn; } else { NN t(z._nn); t -= _nn; _nn = std::move(t); if (_nn.is_zero()) _neg = false; else _neg = !_neg; } return *this; } inline ZZ& ZZ::operator*=(const ZZ& z) { if (is_zero()) return *this; if (z.is_zero()) { clear(); return *this; } if (z._neg) _neg = !_neg; _nn *= z._nn; return *this; } inline ZZ& ZZ::operator/=(const ZZ& z) { if (is_zero()) return *this; if (z.is_zero()) throw DivisionByZeroError(to_string()); if (z._neg) _neg = !_neg; _nn /= z._nn; if (_nn.is_zero()) _neg = false; return *this; } inline ZZ& ZZ::operator%=(const ZZ& z) { if (z.is_zero()) throw DivisionByZeroError(to_string()); if (z._neg) _neg = !_neg; _nn %= z._nn; if (_nn.is_zero()) _neg = false; return *this; } inline ZZ& ZZ::operator<<=(unsigned n) { _nn <<= n; return *this; } inline ZZ& ZZ::operator>>=(unsigned n) { _nn >>= n; if (_nn.is_zero()) _neg = false; return *this; } inline ZZ& ZZ::operator|=(const ZZ& z) { _nn |= z._nn; return *this; } inline ZZ& ZZ::operator&=(const ZZ& z) { _nn &= z._nn; if (_nn.is_zero()) _neg = false; return *this; } inline ZZ& ZZ::operator^=(const ZZ& z) { _nn ^= z._nn; if (_nn.is_zero()) _neg = false; return *this; } inline void ZZ::abs() { _neg = false; } inline void ZZ::neg() { if (!is_zero()) _neg = !_neg; } inline void ZZ::sqr() { _neg = false; _nn.sqr(); } inline void ZZ::pow(unsigned n) { if (n % 2 == 0) _neg = false; _nn.pow(n); } inline unsigned long ZZ::no_bits() const { return _nn.no_bits(); } inline unsigned long ZZ::no_digits() const { return _nn.no_digits(); } inline bool ZZ::test(unsigned long bit) const { return _nn.test(bit); } inline void ZZ::set(unsigned long bit) { _nn.set(bit); } inline void ZZ::clear(unsigned long bit) { _nn.clear(bit); if (_nn.is_zero()) _neg = false; } inline bool ZZ::is_zero() const { return _nn.is_zero(); } inline bool ZZ::is_positive() const { if (is_zero()) return false; return !_neg; } inline bool ZZ::is_negative() const { return _neg; } inline bool ZZ::is_even() const { return _nn.is_even(); } inline void ZZ::clear() { _nn.clear(); _neg = false; } inline const NN& ZZ::to_NN() const { assert(!_neg); return _nn; } inline int ZZ::to_int() const { return (is_negative() ? -1 : 1) * static_cast(_nn.to_unsigned()); } inline ::std::ostream& operator<<(::std::ostream& os, const ZZ& z) { unsigned base = 10; if (os.flags() & std::ios::hex) base = 16; if (os.flags() & std::ios::oct) base = 8; return os << z.to_string(base); } inline ::std::istream& operator>>(::std::istream& os, ZZ& z) { unsigned base = 10; if (os.flags() & std::ios::hex) base = 16; if (os.flags() & std::ios::oct) base = 8; std::string s; os >> s; z = ZZ(s, base); return os; } } } #endif ================================================ FILE: cyacas/libyacas_mp/src/limbs_vector.cpp ================================================ #include "yacas/mp/limbs_vector.hpp" #include #include namespace yacas::mp { LimbsVector::LimbsVector() noexcept : m_data(std::array{}), m_size(0), m_capacity(2) { } LimbsVector::LimbsVector(const std::initializer_list& limbs) : LimbsVector() { for (const auto limb : limbs) { push_back(limb); } } LimbsVector::LimbsVector(std::size_t n, Limb value) : m_size(n), m_capacity(n) { if (n <= 2) { m_data = std::array{}; } else { m_data = std::make_unique(n); } std::fill_n(begin(), n, value); } LimbsVector::LimbsVector(const LimbsVector& limbs) : m_size(limbs.size()), m_capacity(limbs.size()) { if (limbs.size() <= 2) { m_data = std::get<0>(limbs.m_data); } else { m_data = std::make_unique(limbs.size()); std::copy(limbs.cbegin(), limbs.cend(), begin()); } } LimbsVector::LimbsVector(LimbsVector&& limbs) noexcept : m_data(std::move(limbs.m_data)), m_size(limbs.m_size), m_capacity(limbs.m_capacity) { limbs.m_size = 0; limbs.m_capacity = 2; } std::strong_ordering LimbsVector::operator<=>(const LimbsVector& that) const noexcept { if (m_size != that.m_size) return m_size <=> that.m_size; for (std::size_t i = 0; i < m_size; ++i) { if (auto cmp = (*this)[i] <=> that[i]; cmp != 0) return cmp; } return std::strong_ordering::equal; } bool LimbsVector::operator==(const LimbsVector& that) const noexcept { return *this <=> that == 0; } bool LimbsVector::operator!=(const LimbsVector& that) const noexcept { return *this <=> that != 0; } LimbsVector& LimbsVector::operator=(const LimbsVector& other) { LimbsVector tmp(other); swap(tmp); return *this; } LimbsVector& LimbsVector::operator=(LimbsVector&& other) noexcept { swap(other); return *this; } void LimbsVector::swap(LimbsVector& other) noexcept { using std::swap; swap(m_data, other.m_data); swap(m_size, other.m_size); swap(m_capacity, other.m_capacity); } void LimbsVector::insert(iterator b, std::size_t n, Limb value) { const std::size_t index = b - begin(); if (m_size + n > m_capacity) _grow(m_size + n); m_size += n; // FIXME: use std::move for (std::size_t i = m_size - n; i-- != index;) (*this)[i + n] = (*this)[i]; std::fill_n(begin() + index, n, value); } void LimbsVector::erase(iterator b, iterator e) { assert(b >= begin() && e <= end() && b <= e); const std::size_t n = e - b; std::move(e, end(), b); m_size -= n; if (m_size <= 2) { if (m_data.index() == 1) { std::array new_data; std::copy_n( std::get<1>(m_data).get(), m_size, new_data.begin()); m_data = new_data; m_capacity = 2; } } else if (m_size < m_capacity / 2) { std::unique_ptr new_data = std::make_unique(m_capacity / 2); std::copy_n(std::get<1>(m_data).get(), m_size, new_data.get()); m_data = std::move(new_data); m_capacity /= 2; } } LimbsVector::reverse_iterator LimbsVector::rbegin() { return std::make_reverse_iterator(end()); } LimbsVector::reverse_iterator LimbsVector::rend() { return std::make_reverse_iterator(begin()); } LimbsVector::const_reverse_iterator LimbsVector::crbegin() const { return std::make_reverse_iterator(cend()); } LimbsVector::const_reverse_iterator LimbsVector::crend() const { return std::make_reverse_iterator(cbegin()); } std::size_t LimbsVector::size() const noexcept { return m_size; } bool LimbsVector::empty() const noexcept { return m_size == 0; } LimbsVector::Limb* LimbsVector::data() { if (m_data.index() == 0) return std::get<0>(m_data).data(); else return std::get<1>(m_data).get(); } const LimbsVector::Limb* LimbsVector::data() const { if (m_data.index() == 0) return std::get<0>(m_data).data(); else return std::get<1>(m_data).get(); } LimbsVector::Limb& LimbsVector::operator[](std::size_t index) { assert(index < m_size); if (m_data.index() == 0) return std::get<0>(m_data)[index]; else return std::get<1>(m_data)[index]; } const LimbsVector::Limb& LimbsVector::operator[](std::size_t index) const { assert(index < m_size); if (m_data.index() == 0) return std::get<0>(m_data)[index]; else return std::get<1>(m_data)[index]; } LimbsVector::Limb& LimbsVector::front() { assert(m_size > 0); if (m_data.index() == 0) return std::get<0>(m_data)[0]; else return std::get<1>(m_data)[0]; } const LimbsVector::Limb& LimbsVector::front() const { assert(m_size > 0); if (m_data.index() == 0) return std::get<0>(m_data)[0]; else return std::get<1>(m_data)[0]; } LimbsVector::Limb& LimbsVector::back() { assert(m_size > 0); if (m_data.index() == 0) return std::get<0>(m_data)[m_size - 1]; else return std::get<1>(m_data)[m_size - 1]; } const LimbsVector::Limb& LimbsVector::back() const { assert(m_size > 0); if (m_data.index() == 0) return std::get<0>(m_data)[m_size - 1]; else return std::get<1>(m_data)[m_size - 1]; } void LimbsVector::clear() { m_data = std::array{}; m_size = 0; m_capacity = 2; } void LimbsVector::push_back(Limb limb) { if (m_size == m_capacity) _grow(m_capacity * 2); if (m_data.index() == 0) std::get<0>(m_data)[m_size++] = limb; else std::get<1>(m_data)[m_size++] = limb; } void LimbsVector::pop_back() { assert(m_size > 0); m_size -= 1; if (m_data.index() == 1) { if (m_size <= 2) { std::array new_data; std::copy_n( std::get<1>(m_data).get(), m_size, new_data.begin()); m_data = new_data; m_capacity = 2; } else if (m_size < m_capacity / 2) { std::unique_ptr new_data = std::make_unique(m_capacity / 2); std::copy_n(std::get<1>(m_data).get(), m_size, new_data.get()); m_data = std::move(new_data); m_capacity /= 2; } } } void LimbsVector::resize(std::size_t n, Limb value) { if (n > m_size) { if (n > m_capacity) _grow(n); std::fill_n(end(), n - m_size, value); m_size = n; } else if (n < m_size) { m_size = n; if (m_data.index() == 1) { if (n <= 2) { std::array new_data; for (std::size_t i = 0; i < m_size; ++i) new_data[i] = std::get<1>(m_data)[i]; m_data = new_data; m_capacity = 2; } else if (n < m_capacity / 2) { std::unique_ptr new_data = std::make_unique(m_capacity / 2); for (std::size_t i = 0; i < m_size; ++i) new_data[i] = std::get<1>(m_data)[i]; m_data = std::move(new_data); m_capacity /= 2; } } } } void LimbsVector::reserve(std::size_t new_capacity) { if (new_capacity > m_capacity) _grow(new_capacity); } void LimbsVector::_grow(std::size_t new_capacity) { assert(new_capacity > m_capacity); if (new_capacity > 2) { std::unique_ptr new_data = std::make_unique(new_capacity); std::copy_n(data(), m_size, new_data.get()); m_data = std::move(new_data); } m_capacity = new_capacity; } LimbsVector::iterator LimbsVector::begin() noexcept { return data(); } LimbsVector::iterator LimbsVector::end() noexcept { return data() + m_size; } LimbsVector::const_iterator LimbsVector::begin() const noexcept { return data(); } LimbsVector::const_iterator LimbsVector::end() const noexcept { return data() + m_size; } LimbsVector::const_iterator LimbsVector::cbegin() const { return data(); } LimbsVector::const_iterator LimbsVector::cend() const { return data() + m_size; } } ================================================ FILE: cyacas/libyacas_mp/src/nn.cpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ #include "yacas/mp/nn.hpp" #include namespace { using namespace yacas::mp; typedef NN::Limb Limb; typedef NN::Limb2 Limb2; static constexpr int LIMB_BITS = sizeof(Limb) * CHAR_BIT; void _mul(const Limb* __restrict p, unsigned n, Limb a, Limb* __restrict r) { if (n == 1) { const Limb2 v = static_cast(*p) * a; r[0] = static_cast(v); r[1] = static_cast(v >> LIMB_BITS); return; } Limb carry = 0; for (unsigned j = 0; j < n; ++j) { const Limb2 v = static_cast(*p++) * a + carry; carry = static_cast(v >> LIMB_BITS); *r += static_cast(v); carry += *r++ < static_cast(v); } while (carry) { const Limb v = *r + carry; carry = v < *r; *r++ = v; } } bool ssub(NN& a, const NN& b) { if (a >= b) { a -= b; return true; } NN t(a); a = b; a -= t; return false; } void sadd(NN& a, bool& ap, const NN& b, bool bp) { if (ap == bp) { a += b; return; } if (ap && !bp) { ap = ssub(a, b); return; } NN t(a); a = b; ap = ssub(a, t); } void ssub(NN& a, bool& ap, const NN& b, bool bp) { sadd(a, ap, b, !bp); return; } const Limb2 log2x2to31[] = { 2147483648, 1354911328, 1073741824, 924870866, 830760077, 764949109, 715827882, 677455664, 646456993, 620761987, 599025414, 580332017, 564035581, 549665672, 536870912, 525383038, 514993350, 505536792, 496880929, 488918136, 481559945, 474732891, 468375400, 462435433, 456868671, 451637109, 446707947, 442052706, 437646531, 433467612, 429496729, 425716864, 422112891, 418671311, 415380038}; } namespace yacas { namespace mp { const NN NN::ZERO = NN(0u); const NN NN::ONE = NN(1u); const NN NN::TWO = NN(2u); const NN NN::TEN = NN(10u); unsigned NN::MUL_TOOM22_THRESHOLD = 32; unsigned NN::MUL_TOOM33_THRESHOLD = 48; unsigned NN::PARSE_DC_THRESHOLD = 512; unsigned NN::TO_STRING_DC_THRESHOLD = 24; unsigned NN::DIV_REM_DC_THRESHOLD = 4; NN::NN(std::string_view s, unsigned b) { auto p = s.cbegin(); const auto q = s.cend(); while (p != q && std::isspace(*p)) p += 1; if (p == q) throw ParseError(s, s.length()); while (p != q && std::isalnum(*p)) { const char c = *p++; const Limb d = std::isdigit(c) ? Limb(c - '0') : Limb((c | 0x20) - 'a' + 10); if (d >= b) throw ParseError(s, std::distance(s.cbegin(), q)); mul(b); add(d); } drop_zeros(); } std::string NN::to_string(unsigned base) const { assert(base > 1); assert(base <= 36); return _limbs.size() < TO_STRING_DC_THRESHOLD ? to_string_bc(base) : to_string_dc(base); } std::string NN::to_string_bc(unsigned base) const { assert(base > 1); assert(base <= 36); if (_limbs.empty()) return "0"; if (base == 10 && _limbs.size() == 1) return std::to_string(_limbs.back()); if (base == 10 && _limbs.size() == 2) return std::to_string( (static_cast(_limbs.back()) << LIMB_BITS) + _limbs.front()); NN t(*this); std::string s; while (!t._limbs.empty()) { const Limb r = t.div_rem(base); s += r <= 9 ? r + '0' : r - 10 + 'a'; } std::reverse(s.begin(), s.end()); return s; } std::string NN::to_string_dc(unsigned base) const { assert(base > 1); assert(base <= 36); if (_limbs.size() < 3) return to_string(base); const unsigned k = (no_bits() * log2x2to31[base - 2]) >> 32; NN Bk(base); Bk.pow(k); NN Q(*this); const NN R = Q.div_rem(Bk); const std::string r = R.to_string(base); return Q.to_string(base) + std::string(k - r.length(), '0') + r; } void NN::shift_left(unsigned n) { if (n >= LIMB_BITS) { _limbs.insert(_limbs.begin(), n / LIMB_BITS, 0); n %= LIMB_BITS; } if (!n) return; Limb c = 0; for (LimbsVector::iterator i = _limbs.begin(); i != _limbs.end(); ++i) { const Limb2 t = static_cast(*i) << n; *i = static_cast(t) + c; c = static_cast(t >> LIMB_BITS); } if (c) _limbs.push_back(c); } void NN::shift_right(unsigned n) { if (n >= LIMB_BITS) { _limbs.erase(_limbs.begin(), _limbs.begin() + n / LIMB_BITS); n %= LIMB_BITS; } if (!n) return; Limb c = 0; for (LimbsVector::reverse_iterator i = _limbs.rbegin(); i != _limbs.rend(); ++i) { const Limb t = *i << (LIMB_BITS - n); *i = (*i >> n) + c; c = t; } drop_zeros(); } void NN::add(Limb a) { if (a == 0) return; if (_limbs.empty()) { _limbs.push_back(a); return; } _limbs.push_back(0); Limb* __restrict p = _limbs.data(); Limb v = *p + a; Limb carry = v < *p; *p++ = v; while (carry) { v = *p + carry; carry = v < *p; *p++ = v; } drop_zeros(); } void NN::sub(Limb a) { if (a == 0) return; assert(!_limbs.empty()); Limb* __restrict p = _limbs.data(); Limb v = *p - a; Limb borrow = v > *p; *p++ = v; while (borrow) { assert(p < _limbs.data() + _limbs.size()); const Limb v = *p - borrow; borrow = v > *p; *p++ = v; } drop_zeros(); } void NN::mul(Limb b) { if (_limbs.empty()) return; if (b == 0) { _limbs.clear(); return; } const unsigned n = static_cast(_limbs.size()); _limbs.push_back(0); Limb* __restrict p = _limbs.data(); Limb carry = 0; for (unsigned i = 0; i < n; ++i) { const Limb2 v = static_cast(*p) * b + carry; carry = static_cast(v >> LIMB_BITS); *p++ = static_cast(v); } while (carry) { const Limb v = *p + carry; carry = v < *p; *p++ = v; } drop_zeros(); } void NN::div(Limb a) { div_rem(a); } void NN::rem(Limb a) { _limbs = {div_rem(a)}; drop_zeros(); } NN::Limb NN::div_rem(Limb a) { if (a == 0) throw DivisionByZeroError(to_string()); const unsigned n = static_cast(_limbs.size()); LimbsVector q(n, 0); Limb2 t = 0; const Limb* __restrict p = _limbs.data() + n - 1; Limb* __restrict qp = q.data() + n - 1; for (unsigned i = 0; i < n; ++i) { t <<= LIMB_BITS; t += *p--; *qp-- = static_cast(t / a); t %= a; } _limbs = std::move(q); drop_zeros(); return static_cast(t); } void NN::add(const NN& a, unsigned shift) { if (this == &a) { if (shift == 0) shift_left(1); else add(NN(a), shift); return; } if (a.is_zero()) return; if (is_zero()) { _limbs = a._limbs; shift_left(shift); return; } const std::size_t na = a._limbs.size(); if (na + shift > _limbs.size()) _limbs.resize(na + shift + 1, 0); else _limbs.push_back(0); Limb* __restrict p = _limbs.data() + shift; const Limb* __restrict q = a._limbs.data(); Limb carry = 0; for (unsigned i = 0; i < na; ++i) { const Limb v = *p + *q++ + carry; carry = v < *p; *p++ = v; assert(p <= _limbs.data() + _limbs.size()); } while (carry) { const Limb v = *p + carry; carry = v < *p; *p++ = v; assert(p <= _limbs.data() + _limbs.size()); } drop_zeros(); } void NN::sub(const NN& a, unsigned shift) { #ifndef NDEBUG NN aa(a); aa.shift_left(shift); assert(*this >= aa); #endif if (a.is_zero()) return; if (this == &a) { assert(shift == 0); clear(); return; } const std::size_t na = a._limbs.size(); if (na + shift > _limbs.size()) _limbs.resize(na + shift + 1, 0); else _limbs.push_back(0); Limb* __restrict p = _limbs.data() + shift; const Limb* __restrict q = a._limbs.data(); Limb borrow = 0; for (unsigned i = 0; i < na; ++i) { const Limb v = *p - *q++ - borrow; borrow = v > *p; *p++ = v; assert(p <= _limbs.data() + _limbs.size()); } while (borrow) { const Limb v = *p - borrow; borrow = v > *p; *p++ = v; assert(p <= _limbs.data() + _limbs.size()); } drop_zeros(); } void NN::mul(const NN& a) { mul_bc(a); } void NN::mul_bc(const NN& a) { const unsigned m = static_cast(_limbs.size()); const unsigned n = static_cast(a._limbs.size()); LimbsVector result(m + n, 0); Limb* __restrict r = result.data(); if (m >= n) { const Limb* __restrict p = _limbs.data(); for (unsigned i = 0; i < n; ++i) if (const Limb u = a._limbs[i]) _mul(p, m, u, r + i); } else { const Limb* __restrict q = a._limbs.data(); for (unsigned i = 0; i < m; ++i) if (const Limb u = _limbs[i]) _mul(q, n, u, r + i); } _limbs = std::move(result); drop_zeros(); } void NN::sqr() { const unsigned n = static_cast(_limbs.size()); if (n < MUL_TOOM22_THRESHOLD) sqr_bc(); else if (n < MUL_TOOM33_THRESHOLD) sqr_toom22(); else sqr_toom33(); } void NN::sqr_bc() { if (_limbs.empty()) return; const unsigned n = static_cast(_limbs.size()); LimbsVector c(2 * n, 0); const Limb* __restrict p = _limbs.data(); Limb* __restrict r = c.data(); for (unsigned i = 0; i < n; ++i) if (const Limb u = p[i]) _mul(p, n, u, r + i); _limbs = std::move(c); drop_zeros(); } void NN::sqr_toom22() { const unsigned n = static_cast(_limbs.size()); assert(n >= 2); const unsigned k = n / 2; NN x0, x1; x1._limbs.assign(_limbs.begin(), _limbs.begin() + k); x1.drop_zeros(); x0._limbs.assign(_limbs.begin() + k, _limbs.end()); x0.drop_zeros(); NN d; if (x0 < x1) { d = x1; d.sub(x0); } else { d = x0; d.sub(x1); } d.sqr(); x0.sqr(); x1.sqr(); _limbs = x1._limbs; x1.add(x0); add(x1, k); add(x0, 2 * k); sub(d, k); } void NN::sqr_toom33() { const unsigned n = static_cast(_limbs.size()); assert(n >= 3); const unsigned k = (n + 1) / 3; NN x0, x1, x2; x0._limbs.assign(_limbs.begin(), _limbs.begin() + k); x0.drop_zeros(); x1._limbs.assign(_limbs.begin() + k, _limbs.begin() + 2 * k); x1.drop_zeros(); x2._limbs.assign(_limbs.begin() + 2 * k, _limbs.end()); x2.drop_zeros(); // p0 <- x0 NN p0(x0); // t <- x0 + x2 NN t(x0); t += x2; // p1 <- t + x1 NN p1(t); p1 += x1; // p_1 <- t - x1 NN p_1(t); bool p_1p = ssub(p_1, x1); // p_2 <- (p_1 + x2) * 2 − x0 NN p_2(p_1); bool p_2p = p_1p; sadd(p_2, p_2p, x2, true); p_2.shift_left(1); ssub(p_2, p_2p, x0, true); NN pi(x2); pi.sqr(); p_2.sqr(); p1.sqr(); p_1.sqr(); p0.sqr(); NN r0(p0); NN r4(pi); // r3 <- (p_2 - p1) / 3 NN r3(p_2); bool r3p = ssub(r3, p1); r3.div(3); // r1 <- (p1 - p_1) / 2 NN r1(p1); bool r1p = ssub(r1, p_1); r1.shift_right(1); // r2 <- p_1 - r0 NN r2(p_1); bool r2p = ssub(r2, r0); // r3 <- (r2 − r3)/2 + 2 * pi r3p = !r3p; sadd(r3, r3p, r2, r2p); r3.shift_right(1); pi.shift_left(1); sadd(r3, r3p, pi, true); // r2 <- r2 + r1 - r4 sadd(r2, r2p, r1, r1p); ssub(r2, r2p, r4, true); // r1 <- r1 - r3 ssub(r1, r1p, r3, r3p); _limbs = r0._limbs; if (r1p) add(r1, k); if (r2p) add(r2, 2 * k); if (r3p) add(r3, 3 * k); add(r4, 4 * k); if (!r1p) sub(r1, k); if (!r2p) sub(r2, 2 * k); if (!r3p) sub(r3, 3 * k); } void NN::pow(unsigned n) { NN a(ONE); _limbs.swap(a._limbs); while (n) { if (n % 2) { mul(a); n -= 1; } a.sqr(); n /= 2; } } void NN::div(const NN& d) { div_rem(d); } void NN::rem(const NN& d) { _limbs = std::move(div_rem(d)._limbs); } NN NN::div_rem(const NN& d) { if (d.is_zero()) throw DivisionByZeroError(to_string()); if (*this < d) { NN r; r._limbs.swap(_limbs); return r; } if (*this == d) { *this = ONE; return ZERO; } return div_rem_bc(d); } NN NN::div_rem_bc(const NN& d) { assert(!d.is_zero()); NN A(*this); NN B(d); #ifdef _MSC_VER unsigned long index = 0; _BitScanReverse(&index, B._limbs.back()); const unsigned k = 31 - index; #else const unsigned k = __builtin_clz(B._limbs.back()); #endif B <<= k; A <<= k; const unsigned n = static_cast(B._limbs.size()); const unsigned m = static_cast(A._limbs.size() - n); B._limbs.insert(B._limbs.begin(), m, 0); _limbs.clear(); if (A >= B) { _limbs.resize(m + 1, 0); _limbs[m] = 1; A -= B; } else { _limbs.resize(m, 0); } if (A.is_zero()) { drop_zeros(); return ZERO; } const Limb B_leading_digit = B._limbs.back(); for (unsigned jj = 0; jj < m; ++jj) { const unsigned j = m - 1 - jj; Limb2 qs = 0; if (n + j < A._limbs.size()) { qs = A._limbs[n + j]; qs <<= LIMB_BITS; if (n + j < A._limbs.size() + 1) qs += A._limbs[n + j - 1]; } qs /= B_leading_digit; _limbs[j] = static_cast(std::min(qs, static_cast(LIMB_MAX))); NN T; for (;;) { T._limbs.assign(B._limbs.begin() + jj + 1, B._limbs.end()); T *= _limbs[j]; if (A >= T) break; _limbs[j] -= 1; } A -= T; } drop_zeros(); A >>= k; return A; } NN gcd(NN a, NN b) { NN t; while (!b.is_zero()) { t = b; b = a; b %= t; a = t; } return a; } } } ================================================ FILE: cyacas/libyacas_mp/src/rr.cpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesset General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ ================================================ FILE: cyacas/libyacas_mp/src/zz.cpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ #include "yacas/mp/zz.hpp" #include namespace yacas { namespace mp { const ZZ ZZ::ZERO = ZZ(0); const ZZ ZZ::ONE = ZZ(1); const ZZ ZZ::TWO = ZZ(2); const ZZ ZZ::TEN = ZZ(10); ZZ::ZZ(std::string_view s, unsigned b) : _neg(false) { auto p = s.cbegin(); const auto q = s.cend(); while (p != q && std::isspace(*p)) p += 1; if (p == q) throw ParseError(s, s.length()); if (*p == '+') { p += 1; } else if (*p == '-') { _neg = true; p += 1; } try { _nn = NN(std::string_view(&(*p), std::distance(p, q)), b); } catch (const NN::ParseError& e) { throw ParseError(&(*p), std::distance(p, q)); } if (_nn.is_zero()) _neg = false; } std::string ZZ::to_string(unsigned b) const { std::string s = _neg && !is_zero() ? "-" : ""; return s + _nn.to_string(b); } } } ================================================ FILE: cyacas/libyacas_mp/test/CMakeLists.txt ================================================ # # Copyright (C) 2017 Grzegorz Mazur # # This file is part of yacas. # Yacas is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesset General Public License as # published by the Free Software Foundation, either version 2.1 # of the License, or (at your option) any later version. # # Yacas is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with yacas. If not, see . # # find_package (GTest REQUIRED) add_executable (yacas_mp_test src/nn_test.cpp src/zz_test.cpp) target_link_libraries (yacas_mp_test libyacas_mp GTest::GTest GTest::Main) gtest_add_tests (yacas_mp_test "" AUTO) ================================================ FILE: cyacas/libyacas_mp/test/src/nn_test.cpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesset General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ #include "yacas/mp/zz.hpp" #include using namespace yacas::mp; TEST(YMP_NNTest, construction) { ASSERT_TRUE(NN("0").is_zero()); ASSERT_EQ(NN("123"), NN(123u)); ASSERT_EQ(NN(" 123"), NN(123u)); ASSERT_EQ(NN("FF", 16), NN("255")); ASSERT_EQ(NN("ff", 16), NN("255")); ASSERT_EQ(NN("deadbeef", 16), NN("3735928559")); ASSERT_THROW(NN(""), NN::ParseError); ASSERT_THROW(NN(" "), NN::ParseError); ASSERT_THROW(NN("deadbeef", 15), NN::ParseError); } TEST(YMP_NNTest, is_zero) { ASSERT_TRUE(NN(0u).is_zero()); ASSERT_FALSE(NN(1u).is_zero()); ASSERT_FALSE(NN("4294967296").is_zero()); } TEST(YMP_NNTest, comparison) { ASSERT_TRUE(NN("735") == NN(735u)); ASSERT_TRUE(NN("736") != NN("735")); ASSERT_TRUE(NN("736") > NN("735")); ASSERT_TRUE(NN("736") >= NN("735")); } TEST(YMP_NNTest, parity) { ASSERT_TRUE(NN(0u).is_even()); ASSERT_FALSE(NN(1u).is_even()); ASSERT_TRUE(NN(2u).is_even()); ASSERT_FALSE(NN(3u).is_even()); } TEST(YMP_NNTest, to_string) { ASSERT_EQ(NN(0u).to_string(10), "0"); ASSERT_EQ(NN(1u).to_string(10), "1"); ASSERT_EQ(NN(2u).to_string(10), "2"); ASSERT_EQ(NN("18446744073709551616").to_string(), "18446744073709551616"); ASSERT_EQ( NN("121932631356500531591068431703703700581771069347203169112635269") .to_string(), "121932631356500531591068431703703700581771069347203169112635269"); ASSERT_EQ(NN("3735928559").to_string(16), "deadbeef"); ASSERT_EQ( NN("121932631356500531591068431703703700581771069347203169112635269") .to_string(), "121932631356500531591068431703703700581771069347203169112635269"); } TEST(YMP_NNTest, io) { std::ostringstream os; os << std::hex << NN("3735928559"); ASSERT_EQ(os.str(), "deadbeef"); os.str(""); os.clear(); os << std::oct << NN("3735928559"); ASSERT_EQ(os.str(), "33653337357"); } TEST(YMP_NNTest, shift) { NN a; a = NN(5); a <<= 1; ASSERT_EQ(a, NN(10)); a = NN(5); a >>= 1; ASSERT_EQ(a, NN(2)); a = NN("121932631356500531591068431703703700581771069347203169112635268"); a >>= 1; ASSERT_EQ( a, NN("60966315678250265795534215851851850290885534673601584556317634")); a <<= 37; ASSERT_EQ( a, NN("8379146623862302403044060157846671297166126665682970886501213062979125248")); a >>= 32; ASSERT_EQ( a, NN("1950922101704008505457094907259259209308337109555250705802164288")); } TEST(YMP_NNTest, sqr) { NN a; a.sqr(); ASSERT_EQ(a, NN::ZERO); a = NN(5); a.sqr(); ASSERT_EQ(a, NN("25")); a = NN("1562953088685537097059913193583733507649747348170814625952201"); a.sqr(); ASSERT_EQ( a, NN("2442822357431660390046655205292608987306861461763843847861569410791" "671541750358984338534812651100785465086339385936744401")); a = NN("1667703557600363725046376676090748681843605861855768202333970544912" "5918899"); a.sqr(); ASSERT_EQ(a, NN("2781235156032909688867661347708318236031357056471990889749656" "8874577914400268908763247285607086599717046124954345677502282" "2347627260616871125372201")); a.sqr(); ASSERT_EQ(a, NN("7735268993153403503304606191118795696610949078309176540718091" "8697187558629814838215212696461020230376125043081229650956490" "7199281643513660336004802212689814512583461474131759251703924" "1448510014854449620623685195394076123932122239019841816567816" "5748977200849860077295483412916485724330783584401")); a = NN("43298432840974328947183271491541079320475403764598753914325843075329" "85041258796438702654310726508743652874365432087655736345012364756043" "81753408315620873167430821540810560872643218756743810564783105825648" "74056087436587431065731486504375673456743053247885032856087432065310" "87564398204357520436574325863520007434365308725624380653765208734132" "46475659873589327902573743285932585467423285984375932575852094237923" "579328"); a.sqr(); ASSERT_EQ(a, NN("187475428648436429856831489259327536436520448042946087510189029" "508938780965513552632980143411535002947654949460620663344635790" "556377422365029345765733894771796962944560922729298314258140552" "929369408117002607439027128831914911354137217799235321698085404" "005442143761335597185337908611893721164171813516683980879772274" "862485082671460833262731384783122158289313793496453424229418477" "994889974902044275544841799735966023054440842435704344714181994" "613927594359524428405377856257194202888469364705167511792141640" "532726328300226911110011094535694877421493842649850484322056237" "900295096809510203923061353581327350260262295074165065947916753" "169818423862934362386660760025589538715872105323918909971201848" "819723597348997720621263653492740044130493923227011660433942814" "829917409985490369529307633336067725045689754286184615455264247" "108931584")); NN b{a}; a.sqr(); b *= b; ASSERT_EQ(a, b); a.sqr(); b *= b; ASSERT_EQ(a, b); } TEST(YMP_NNTest, mul) { NN a(10); a *= 10; ASSERT_EQ(a, NN(100)); a *= 10; ASSERT_EQ(a, NN(1000)); a *= 10; ASSERT_EQ(a, NN(10000)); a *= 100; ASSERT_EQ(a, NN(1000000)); a *= 100; ASSERT_EQ(a, NN(100000000)); a *= 100; ASSERT_EQ(a, NN("10000000000")); a *= 100; ASSERT_EQ(a, NN("1000000000000")); a *= 100; ASSERT_EQ(a, NN("100000000000000")); a *= 753; ASSERT_EQ(a, NN("75300000000000000")); NN b(10); a *= b; ASSERT_EQ(a, NN("753000000000000000")); NN x("4294967296"); NN y("4294967296"); x *= y; ASSERT_EQ(x, NN("18446744073709551616")); x = NN("123456789123456789123456789"); y = NN("987654321987654321987654321987654321"); x *= y; ASSERT_EQ( x, NN("121932631356500531591068431703703700581771069347203169112635269")); } TEST(YMP_NNTest, pow) { NN a("1234567890123456789"); a.pow(7); ASSERT_EQ( a, NN("4371241899268725428364208289519510588539212553598950486912858825153" "547618526426094549436384682321156604105518810510686881926429")); } TEST(YMP_NNTest, div_rem) { NN a(123); ASSERT_THROW(a /= 0, std::domain_error); ASSERT_EQ(a /= 1, NN(123)); ASSERT_EQ(a /= 123, NN::ONE); a = NN("123"); ASSERT_EQ(a /= 10, NN(12)); ASSERT_EQ(a /= 6, NN(2)); a = NN("12314324325435664576576568787687576435342431432545345"); a /= 743; ASSERT_EQ(a, NN("16573787786589050574127279660413965592654685642725")); a = NN(123); ASSERT_THROW(a /= NN::ZERO, std::domain_error); ASSERT_EQ((a /= NN(1)), NN(123)); ASSERT_EQ((a /= NN(123)), NN::ONE); a = NN("123"); ASSERT_EQ((a /= NN(10)), NN(12)); ASSERT_EQ((a /= NN(6)), NN(2)); a = NN("1125899906842624"); NN b("562949953421312"); a /= b; ASSERT_EQ(a, NN::TWO); a = NN("79228162514264337593543950335"); b = NN("39614081257132168796771975168"); a /= b; ASSERT_EQ(a, NN::ONE); a = NN("79228162514264337593543950336"); b = NN("39614081257132168796771975168"); a /= b; ASSERT_EQ(a, NN::TWO); a = NN("12314324325435664576576568787687576435342431432545345"); b = NN("42345346452431432543645634543455434"); a /= b; ASSERT_EQ(a, NN("290807027385380782")); a = NN(1); for (int i = 1; i <= 20; ++i) a *= NN(i); b = NN(1); for (int i = 1; i <= 10; ++i) b *= NN(i); a /= b; ASSERT_EQ(a, NN("670442572800")); a = NN(1); for (int i = 1; i <= 50; ++i) a *= NN(i); b = NN(1); for (int i = 1; i <= 40; ++i) b *= NN(i); a /= b; ASSERT_EQ(a, NN("37276043023296000")); a = NN(1); for (int i = 1; i <= 100; ++i) a *= NN(i); b = NN(1); for (int i = 1; i <= 90; ++i) b *= NN(i); a /= b; ASSERT_EQ(a, NN("62815650955529472000")); a = NN(1); for (int i = 1; i <= 150; ++i) a *= NN(i); b = NN(1); for (int i = 1; i <= 140; ++i) b *= NN(i); a /= b; ASSERT_EQ(a, NN("4244078637389118528000")); a = NN(1); for (int i = 1; i <= 180; ++i) a *= NN(i); ASSERT_EQ( a, NN("2008960624991342996569513368984668389175403407988677779404353351600" "4486095339598094118013811209730973563159410103739960967103213218633" "1495273609598531966730972945653558819806475064353856858157445040809" "2095603584633196446648911142564300178241417967538181923386423026933" "27818731986039603200000000000000000000000000000000000000000000")); b = NN(1); for (int i = 1; i <= 170; ++i) b *= NN(i); ASSERT_EQ( b, NN("7257415615307998967396728211129263114716991681296451376543577798900" "5618434017061578523507492426174595114909912378385207766660225654427" "5302532890077320751090240043028005829560396661259965825710439855829" "4257568966313439612262571094946806711205568880457193340212661452800" "000000000000000000000000000000000000000")); a /= b; ASSERT_EQ(a, NN("27681487894311318144000")); a = NN("1234567890123456789"); b = NN("987654321"); a /= b; ASSERT_EQ(a, NN("1249999988")); a = NN("281512773099640599001078059567905818350"); b = NN("72873402435871630350805926803788103957"); a /= b; ASSERT_EQ(a, NN("3")); a = NN("123456789012345678901234567890123456789012345678901234567890123456" "789012345678901234567890123456789012345678901234567890123456789012" "345678901234567890123456789012345678901234567890123456789012345678" "901234567890123456789012345678901234567890123456789012345678901234" "567890123456789012345678901234567890123456789012345678901234567890" "123456789012345678901234567890123456789012345678901234567890123456" "789012345678901234567890123456789012345678901234567890123456789012" "345678901234567890123456789012345678901234567890123456789012345678" "901234567890123456789012345678901234567890123456789012345678901234" "567890123456789012345678901234567890123456789012345678901234567890" "123456789012345678901234567890123456789012345678901234567890123456" "789012345678901234567890123456789012345678901234567890123456789012" "345678901234567890123456789012345678901234567890123456789012345678" "901234567890123456789012345678901234567890123456789012345678901234" "567890123456789012345678901234567890123456789012345678901234567890" "123456789012345678901234567890123456789012345678901234567890123456" "789012345678901234567890123456789012345678901234567890123456789012" "345678901234567890123456789012345678901234567890123456789012345678" "901234567890123456789012345678901234567890123456789012345678901234" "567890123456789012345678901234567890123456789012345678901234567890" "123456789012345678901234567890123456789012345678901234567890123456" "789012345678901234567890123456789012345678901234567890123456789012" "345678901234567890123456789012345678901234567890123456789012345678" "901234567890123456789012345678901234567890123456789012345678901234" "567890123456789012345678901234567890123456789012345678901234567890" "123456789012345678901234567890123456789012345678901234567890123456" "789012345678901234567890123456789012345678901234567890123456789012" "345678901234567890123456789012345678901234567890123456789012345678" "901234567890123456789012345678901234567890123456789012345678901234" "5678901234567890123456789012345678901234567890123456789012345678" "9"); b = NN( "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "1234567890123456789012345678901234567890123456789012345678901234567890" "123456789"); a /= b; ASSERT_EQ(a, NN("1000000000000000000000000000000000000000000000000000000000000" "00000000000000000000")); a = NN("340282366920938463463374607431768211456"); b = NN("4"); a /= b; ASSERT_EQ(a, NN("85070591730234615865843651857942052864")); a = NN(3); ASSERT_THROW(a %= 0, std::domain_error); a %= NN(2); ASSERT_EQ(a, NN("1")); a = NN("12314324325435664576576568787687576435342431432545345"); a %= 743; ASSERT_EQ(a, NN(670)); a = NN("1234567890123456789"); b = NN("987654321"); a %= b; ASSERT_EQ(a, NN("725308641")); a = NN("2618461302565558051873150214470675720371752830764642155368330885104190000"); b = NN("141326557078049505524642968688"); a /= b; ASSERT_EQ(a, NN("18527737155016642260898961793617744820333125")); } TEST(YMP_NNTest, bitwise) {} TEST(YMP_NNTest, no_digits) { ASSERT_EQ(NN().no_digits(), 1); ASSERT_EQ(NN("1234567890123456789").no_digits(), 19); ASSERT_EQ( NN("12314324325435664576576568787687576435342431432545345").no_digits(), 53); NN a = NN(10); a.pow(93); ASSERT_EQ(a.no_digits(), 94); a -= 1; ASSERT_EQ(a.no_digits(), 93); } TEST(YMP_NNTest, gcd) { NN a(6); NN b(4); NN c; c = gcd(a, b); ASSERT_EQ(c, NN(2)); } ================================================ FILE: cyacas/libyacas_mp/test/src/zz_test.cpp ================================================ /* * * This file is part of yacas. * Yacas is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesset General Public License as * published by the Free Software Foundation, either version 2.1 * of the License, or (at your option) any later version. * * Yacas is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with yacas. If not, see . * */ #include "yacas/mp/zz.hpp" #include using namespace yacas::mp; TEST(YMP_ZZTest, construction) { ASSERT_EQ(ZZ("0"), ZZ(0)); ASSERT_EQ(ZZ("123"), ZZ(123)); ASSERT_EQ(ZZ(" 123"), ZZ(123)); ASSERT_EQ(ZZ("+123"), ZZ(123)); ASSERT_EQ(ZZ("FF", 16), ZZ("255")); ASSERT_EQ(ZZ("-FF", 16), ZZ("-255")); ASSERT_EQ(ZZ("ff", 16), ZZ("255")); ASSERT_EQ(ZZ("-ff", 16), ZZ("-255")); ASSERT_EQ(ZZ("deadbeef", 16), ZZ("3735928559")); ASSERT_EQ(ZZ("-deadbeef", 16), ZZ("-3735928559")); ASSERT_THROW(ZZ(""), ZZ::ParseError); ASSERT_THROW(ZZ(" "), ZZ::ParseError); ASSERT_THROW(ZZ("deadbeef", 15), ZZ::ParseError); } TEST(YMP_ZZTest, is_zero) { ASSERT_TRUE(ZZ(0).is_zero()); ASSERT_FALSE(ZZ(1).is_zero()); ASSERT_FALSE(ZZ(-1).is_zero()); ASSERT_FALSE(ZZ("4294967296").is_zero()); ASSERT_TRUE(ZZ("-0").is_zero()); } TEST(YMP_ZZTest, comparison) { ASSERT_TRUE(ZZ("735") == ZZ(735)); ASSERT_TRUE(ZZ("-735") == ZZ(-735)); ASSERT_TRUE(ZZ("-735") != ZZ(735)); ASSERT_TRUE(ZZ("736") != ZZ("735")); ASSERT_TRUE(ZZ("736") > ZZ("735")); ASSERT_TRUE(ZZ("736") >= ZZ("735")); ASSERT_TRUE(ZZ("736") > ZZ("-736")); ASSERT_TRUE(ZZ("-736") <= ZZ("735")); } TEST(YMP_ZZTest, parity) { ASSERT_TRUE(ZZ(0).is_even()); ASSERT_FALSE(ZZ(1).is_even()); ASSERT_FALSE(ZZ(-1).is_even()); ASSERT_TRUE(ZZ(2).is_even()); ASSERT_TRUE(ZZ(-2).is_even()); ASSERT_FALSE(ZZ(3).is_even()); ASSERT_FALSE(ZZ(-3).is_even()); ASSERT_TRUE(ZZ("167170571948282915479450721253708836308").is_even()); ASSERT_TRUE(ZZ("-167170571948282915479450721253708836308").is_even()); ASSERT_FALSE(ZZ("167170571948282915479450721253708836309").is_even()); ASSERT_FALSE(ZZ("-167170571948282915479450721253708836309").is_even()); } TEST(YMP_ZZTest, to_string) { ASSERT_EQ(ZZ(0).to_string(10), "0"); ASSERT_EQ(ZZ(1).to_string(10), "1"); ASSERT_EQ(ZZ(-1).to_string(10), "-1"); ASSERT_EQ(ZZ(2).to_string(10), "2"); ASSERT_EQ(ZZ(-2).to_string(10), "-2"); ASSERT_EQ(ZZ("18446744073709551616").to_string(), "18446744073709551616"); ASSERT_EQ(ZZ("-18446744073709551616").to_string(), "-18446744073709551616"); ASSERT_EQ(ZZ("121932631356500531591068431703703700581771069347203169112635269").to_string(), "121932631356500531591068431703703700581771069347203169112635269"); ASSERT_EQ(ZZ("-121932631356500531591068431703703700581771069347203169112635269").to_string(), "-121932631356500531591068431703703700581771069347203169112635269"); ASSERT_EQ(ZZ("3735928559").to_string(16), "deadbeef"); ASSERT_EQ(ZZ("-3735928559").to_string(16), "-deadbeef"); } TEST(YMP_ZZTest, io) { std::ostringstream os; os << std::hex << ZZ("3735928559"); ASSERT_EQ(os.str(), "deadbeef"); os.str(""); os.clear(); os << std::oct << ZZ("3735928559"); ASSERT_EQ(os.str(), "33653337357"); } TEST(YMP_ZZTest, shift) { ZZ a; a = ZZ(5); a <<= 1; ASSERT_EQ(a, ZZ(10)); a = ZZ(-5); a <<= 1; ASSERT_EQ(a, ZZ(-10)); a >>= 2; ASSERT_EQ(a, ZZ(-2)); a = ZZ("-121932631356500531591068431703703700581771069347203169112635268"); a >>= 1; ASSERT_EQ(a, ZZ("-60966315678250265795534215851851850290885534673601584556317634")); } TEST(YMP_ZZTest, sqr) { ZZ a; a = ZZ(5); a.sqr(); ASSERT_EQ(a, ZZ("25")); a = ZZ("-1562953088685537097059913193583733507649747348170814625952201"); a.sqr(); ASSERT_EQ(a, ZZ("2442822357431660390046655205292608987306861461763843847861569410791671541750358984338534812651100785465086339385936744401")); a = ZZ("16677035576003637250463766760907486818436058618557682023339705449125918899"); a.sqr(); ASSERT_EQ(a, ZZ("278123515603290968886766134770831823603135705647199088974965688745779144002689087632472856070865997170461249543456775022822347627260616871125372201")); a.sqr(); ASSERT_EQ(a, ZZ("77352689931534035033046061911187956966109490783091765407180918697187558629814838215212696461020230376125043081229650956490719928164351366033600480221268981451258346147413175925170392414485100148544496206236851953940761239321222390198418165678165748977200849860077295483412916485724330783584401")); } TEST(YMP_ZZTest, add) { ZZ a(10); a += 10; ASSERT_EQ(a, 20); a += -21; ASSERT_EQ(a, -1); a += 0; ASSERT_EQ(a, -1); a += -2; ASSERT_EQ(a, -3); a += 4; ASSERT_EQ(a, 1); ZZ x("123456789123456789123456789"); ZZ y("-987654321987654321987654321987654321"); x += y; ASSERT_EQ(x, ZZ("-987654321864197532864197532864197532")); x += ZZ("987654321864197532864197532864197534"); ASSERT_EQ(x, 2); } TEST(YMP_ZZTest, mul) { ZZ a(10); a *= 10; ASSERT_EQ(a, ZZ(100)); a *= 10; ASSERT_EQ(a, ZZ(1000)); a *= 10; ASSERT_EQ(a, ZZ(10000)); a *= 100; ASSERT_EQ(a, ZZ(1000000)); a *= 100; ASSERT_EQ(a, ZZ(100000000)); a *= -100; ASSERT_EQ(a, ZZ("-10000000000")); a *= -100; ASSERT_EQ(a, ZZ("1000000000000")); a *= 100; ASSERT_EQ(a, ZZ("100000000000000")); a *= -753; ASSERT_EQ(a, ZZ("-75300000000000000")); ZZ b(-10); a *= b; ASSERT_EQ(a, ZZ("753000000000000000")); ZZ x("4294967296"); ZZ y("-4294967296"); x *= y; ASSERT_EQ(x, ZZ("-18446744073709551616")); x = ZZ("-123456789123456789123456789"); y = ZZ("-987654321987654321987654321987654321"); x *= y; ASSERT_EQ(x, ZZ("121932631356500531591068431703703700581771069347203169112635269")); } TEST(YMP_ZZTest, pow) { ZZ a("-1234567890123456789"); a.pow(7); ASSERT_EQ(a, ZZ("-4371241899268725428364208289519510588539212553598950486912858825153547618526426094549436384682321156604105518810510686881926429")); } TEST(YMP_ZZTest, div) { ZZ a(-123); ASSERT_THROW(a /= 0, std::domain_error); ASSERT_EQ(a /= 1, ZZ(-123)); ASSERT_EQ(a /= -123, ZZ::ONE); a = ZZ("123"); ASSERT_EQ(a /= 10, ZZ(12)); ASSERT_EQ(a /= -6, ZZ(-2)); a = ZZ("-12314324325435664576576568787687576435342431432545345"); a /= 743; ASSERT_EQ(a, ZZ("-16573787786589050574127279660413965592654685642725")); a = ZZ(-123); ASSERT_THROW(a /= ZZ::ZERO, std::domain_error); ASSERT_EQ((a /= ZZ(1)), ZZ(-123)); ASSERT_EQ((a /= ZZ(123)), ZZ(-1)); a = ZZ("-123"); ASSERT_EQ((a /= ZZ(10)), ZZ(-12)); ASSERT_EQ((a /= ZZ(-6)), ZZ(2)); a = ZZ("-1125899906842624"); ZZ b("-562949953421312"); a /= b; ASSERT_EQ(a, ZZ::TWO); a = ZZ("79228162514264337593543950335"); b = ZZ("39614081257132168796771975168"); a /= b; ASSERT_EQ(a, ZZ::ONE); a = ZZ("-79228162514264337593543950336"); b = ZZ("-39614081257132168796771975168"); a /= b; ASSERT_EQ(a, ZZ::TWO); a = ZZ("-12314324325435664576576568787687576435342431432545345"); b = ZZ("42345346452431432543645634543455434"); a /= b; ASSERT_EQ(a, ZZ("-290807027385380782")); a = ZZ(1); for (int i = 1; i <= 180; ++i) a *= ZZ(-i); ASSERT_EQ(a, ZZ("200896062499134299656951336898466838917540340798867777940435335160044860953395980941180138112097309735631594101037399609671032132186331495273609598531966730972945653558819806475064353856858157445040809209560358463319644664891114256430017824141796753818192338642302693327818731986039603200000000000000000000000000000000000000000000")); b = ZZ(-1); for (int i = 1; i <= 170; ++i) b *= ZZ(i); ASSERT_EQ(b, ZZ("-7257415615307998967396728211129263114716991681296451376543577798900561843401706157852350749242617459511490991237838520776666022565442753025328900773207510902400430280058295603966612599658257104398558294257568966313439612262571094946806711205568880457193340212661452800000000000000000000000000000000000000000")); a /= b; ASSERT_EQ(a, ZZ("-27681487894311318144000")); a = ZZ("1234567890123456789"); b = ZZ("-987654321"); a /= b; ASSERT_EQ(a, ZZ("-1249999988")); a = ZZ("-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); b = ZZ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); a /= b; ASSERT_EQ(a, ZZ("-100000000000000000000000000000000000000000000000000000000000000000000000000000000")); } TEST(YMP_ZZTest, rem) { ZZ a(3); a %= ZZ(2); ASSERT_EQ(a, ZZ("1")); a = ZZ("12314324325435664576576568787687576435342431432545345"); a %= 743; ASSERT_EQ(a, ZZ(670)); a = ZZ("1234567890123456789"); ZZ b("987654321"); a %= b; ASSERT_EQ(a, ZZ("725308641")); } TEST(YMP_ZZTest, no_digits) { ASSERT_EQ(ZZ().no_digits(), 1); ASSERT_EQ(ZZ(1).no_digits(), 1); ASSERT_EQ(ZZ(2).no_digits(), 1); ASSERT_EQ(ZZ(3).no_digits(), 1); ASSERT_EQ(ZZ(4).no_digits(), 1); ASSERT_EQ(ZZ(5).no_digits(), 1); ASSERT_EQ(ZZ(6).no_digits(), 1); ASSERT_EQ(ZZ(7).no_digits(), 1); ASSERT_EQ(ZZ(8).no_digits(), 1); ASSERT_EQ(ZZ(9).no_digits(), 1); ASSERT_EQ(ZZ(10).no_digits(), 2); ASSERT_EQ(ZZ(99).no_digits(), 2); ASSERT_EQ(ZZ(100).no_digits(), 3); ZZ a = ZZ("1234567890123456789"); ASSERT_EQ(a.no_digits(), 19); a = ZZ("-12314324325435664576576568787687576435342431432545345"); ASSERT_EQ(a.no_digits(), 53); a = ZZ(-10); a.pow(93); ASSERT_EQ(a.no_digits(), 94); } TEST(YMP_ZZTest, gcd) { ZZ a(-6); ZZ b(4); ZZ c; c = gcd(a, b); ASSERT_EQ(c, ZZ(2)); } ================================================ FILE: cyacas/packaging/deb/changelog ================================================ yacas (1.9.2-1) UNRELEASED; urgency=low * New upstream release -- Grzegorz Mazur Tue, 4 Aug 2020 19:02:24 +0200 yacas (1.9.1-1) UNRELEASED; urgency=low * New upstream release -- Grzegorz Mazur Wed, 1 Jul 2020 14:04:20 +0200 yacas (1.8.0-1) UNRELEASED; urgency=low * New upstream release -- Grzegorz Mazur Thu, 31 Oct 2019 13:36:20 +0200 ================================================ FILE: cyacas/packaging/deb/compat ================================================ 12 ================================================ FILE: cyacas/packaging/deb/control ================================================ Source: yacas Maintainer: Grzegorz Mazur Section: contrib/math Priority: optional Standards-Version: 4.4.0 Build-Depends: debhelper (>=9), cmake, python3-sphinx, python3-sphinx-rtd-theme, python3-sphinxcontrib.bibtex, qtbase5-dev, qtbase5-dev-tools, qtwebengine5-dev, libqt5webengine5, libqt5svg5-dev, libssl-dev, libzmqpp-dev, libzmq3-dev, libboost-date-time-dev, libboost-filesystem-dev, libboost-program-options-dev, libjsoncpp-dev Homepage: http://www.yacas.org Package: yacas-common Architecture: all Depends: ${misc:Depends} Description: Easy to use, general purpose Computer Algebra System Yacas is an easy to use, general purpose Computer Algebra System, a program for symbolic manipulation of mathematical expressions. It uses its own programming language designed for symbolic as well as arbitrary-precision numerical computations. The system has a library of scripts that implement many of the symbolic algebra operations; new algorithms can be easily added to the library. Yacas comes with extensive documentation covering the scripting language, the functionality that is already implemented in the system, and the algorithms we used. Package: yacas-console Architecture: any Depends: yacas-common (= ${source:Version}), yacas-doc (= ${source:Version}), gnuplot, ${shlibs:Depends}, ${misc:Depends} Description: Easy to use, general purpose Computer Algebra System Yacas is an easy to use, general purpose Computer Algebra System, a program for symbolic manipulation of mathematical expressions. It uses its own programming language designed for symbolic as well as arbitrary-precision numerical computations. The system has a library of scripts that implement many of the symbolic algebra operations; new algorithms can be easily added to the library. Yacas comes with extensive documentation covering the scripting language, the functionality that is already implemented in the system, and the algorithms we used. Package: yacas-gui Architecture: any Depends: yacas-common (= ${source:Version}), yacas-doc (= ${source:Version}), ${shlibs:Depends}, ${misc:Depends}, libjs-jquery, libjs-jquery-ui, libjs-mathjax, fonts-mathjax, libjs-codemirror Description: Graphical User Interface for yacas Yacas is an easy to use, general purpose Computer Algebra System, a program for symbolic manipulation of mathematical expressions. It uses its own programming language designed for symbolic as well as arbitrary-precision numerical computations. The system has a library of scripts that implement many of the symbolic algebra operations; new algorithms can be easily added to the library. Yacas comes with extensive documentation covering the scripting language, the functionality that is already implemented in the system, and the algorithms we used. Package: yacas-kernel Architecture: any Depends: ${shlibs:Depends}, yacas-common (= ${source:Version}), yacas-doc (= ${source:Version}), ${misc:Depends} Description: Yacas kernel for Jupyter Yacas is an easy to use, general purpose Computer Algebra System, a program for symbolic manipulation of mathematical expressions. It uses its own programming language designed for symbolic as well as arbitrary-precision numerical computations. The system has a library of scripts that implement many of the symbolic algebra operations; new algorithms can be easily added to the library. Yacas comes with extensive documentation covering the scripting language, the functionality that is already implemented in the system, and the algorithms we used. Package: yacas-doc Architecture: all Section: contrib/doc Depends: ${misc:Depends}, fonts-lato, fonts-roboto-slab, fonts-glewlwyd, libjs-jquery, libjs-underscore Suggests: yacas-console (= ${binary:Version}), yacas-gui (= ${binary:Version}) Description: Documentation for Yacas Yacas documentation. Yacas is an easy to use, general purpose Computer Algebra System, a program for symbolic manipulation of mathematical expressions. It uses its own programming language designed for symbolic as well as arbitrary-precision numerical computations. The system has a library of scripts that implement many of the symbolic algebra operations; new algorithms can be easily added to the library. Yacas comes with extensive documentation covering the scripting language, the functionality that is already implemented in the system, and the algorithms we used. Package: yacas-dev Architecture: any Section: contrib/devel Depends: ${misc:Depends} Suggests: yacas-console (= ${binary:Version}), yacas-gui (= ${binary:Version}) Description: Development files for Yacas Header files and libraries necessary for yacas development. Yacas is an easy to use, general purpose Computer Algebra System, a program for symbolic manipulation of mathematical expressions. It uses its own programming language designed for symbolic as well as arbitrary-precision numerical computations. The system has a library of scripts that implement many of the symbolic algebra operations; new algorithms can be easily added to the library. Yacas comes with extensive documentation covering the scripting language, the functionality that is already implemented in the system, and the algorithms we used. ================================================ FILE: cyacas/packaging/deb/copyright ================================================ Debian packaging of yacas originally created in 1998 by: John Lapeyre and since 2010 improved and maintained by: Muammar El Khatib This set of debian packaging files was independently created in 2016 by: Grzegorz Mazur to facilitate building out-of-distribution packages of newer yacas versions Upstream source: https://github.com/grzegorzmazur/yacas Copyright: Copyright © 1999-2016 by respective contributors; for the full list of contributors see License: This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with yacas. If not, see . For your convenience, on Debian systems the complete text of the LGPL 2.1 is in /usr/share/common-licenses/LGPL-2.1 ================================================ FILE: cyacas/packaging/deb/missing-sources/jquery-ui.js ================================================ /*! jQuery UI - v1.12.1 - 2016-09-14 * http://jqueryui.com * Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js * Copyright jQuery Foundation and other contributors; Licensed MIT */ (function( factory ) { if ( typeof define === "function" && define.amd ) { // AMD. Register as an anonymous module. define([ "jquery" ], factory ); } else { // Browser globals factory( jQuery ); } }(function( $ ) { $.ui = $.ui || {}; var version = $.ui.version = "1.12.1"; /*! * jQuery UI Widget 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Widget //>>group: Core //>>description: Provides a factory for creating stateful widgets with a common API. //>>docs: http://api.jqueryui.com/jQuery.widget/ //>>demos: http://jqueryui.com/widget/ var widgetUuid = 0; var widgetSlice = Array.prototype.slice; $.cleanData = ( function( orig ) { return function( elems ) { var events, elem, i; for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { try { // Only trigger remove when necessary to save time events = $._data( elem, "events" ); if ( events && events.remove ) { $( elem ).triggerHandler( "remove" ); } // Http://bugs.jquery.com/ticket/8235 } catch ( e ) {} } orig( elems ); }; } )( $.cleanData ); $.widget = function( name, base, prototype ) { var existingConstructor, constructor, basePrototype; // ProxiedPrototype allows the provided prototype to remain unmodified // so that it can be used as a mixin for multiple widgets (#8876) var proxiedPrototype = {}; var namespace = name.split( "." )[ 0 ]; name = name.split( "." )[ 1 ]; var fullName = namespace + "-" + name; if ( !prototype ) { prototype = base; base = $.Widget; } if ( $.isArray( prototype ) ) { prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); } // Create selector for plugin $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { return !!$.data( elem, fullName ); }; $[ namespace ] = $[ namespace ] || {}; existingConstructor = $[ namespace ][ name ]; constructor = $[ namespace ][ name ] = function( options, element ) { // Allow instantiation without "new" keyword if ( !this._createWidget ) { return new constructor( options, element ); } // Allow instantiation without initializing for simple inheritance // must use "new" keyword (the code above always passes args) if ( arguments.length ) { this._createWidget( options, element ); } }; // Extend with the existing constructor to carry over any static properties $.extend( constructor, existingConstructor, { version: prototype.version, // Copy the object used to create the prototype in case we need to // redefine the widget later _proto: $.extend( {}, prototype ), // Track widgets that inherit from this widget in case this widget is // redefined after a widget inherits from it _childConstructors: [] } ); basePrototype = new base(); // We need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from basePrototype.options = $.widget.extend( {}, basePrototype.options ); $.each( prototype, function( prop, value ) { if ( !$.isFunction( value ) ) { proxiedPrototype[ prop ] = value; return; } proxiedPrototype[ prop ] = ( function() { function _super() { return base.prototype[ prop ].apply( this, arguments ); } function _superApply( args ) { return base.prototype[ prop ].apply( this, args ); } return function() { var __super = this._super; var __superApply = this._superApply; var returnValue; this._super = _super; this._superApply = _superApply; returnValue = value.apply( this, arguments ); this._super = __super; this._superApply = __superApply; return returnValue; }; } )(); } ); constructor.prototype = $.widget.extend( basePrototype, { // TODO: remove support for widgetEventPrefix // always use the name + a colon as the prefix, e.g., draggable:start // don't prefix for widgets that aren't DOM-based widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name }, proxiedPrototype, { constructor: constructor, namespace: namespace, widgetName: name, widgetFullName: fullName } ); // If this widget is being redefined then we need to find all widgets that // are inheriting from it and redefine all of them so that they inherit from // the new version of this widget. We're essentially trying to replace one // level in the prototype chain. if ( existingConstructor ) { $.each( existingConstructor._childConstructors, function( i, child ) { var childPrototype = child.prototype; // Redefine the child widget using the same prototype that was // originally used, but inherit from the new version of the base $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); } ); // Remove the list of existing child constructors from the old constructor // so the old child constructors can be garbage collected delete existingConstructor._childConstructors; } else { base._childConstructors.push( constructor ); } $.widget.bridge( name, constructor ); return constructor; }; $.widget.extend = function( target ) { var input = widgetSlice.call( arguments, 1 ); var inputIndex = 0; var inputLength = input.length; var key; var value; for ( ; inputIndex < inputLength; inputIndex++ ) { for ( key in input[ inputIndex ] ) { value = input[ inputIndex ][ key ]; if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { // Clone objects if ( $.isPlainObject( value ) ) { target[ key ] = $.isPlainObject( target[ key ] ) ? $.widget.extend( {}, target[ key ], value ) : // Don't extend strings, arrays, etc. with objects $.widget.extend( {}, value ); // Copy everything else by reference } else { target[ key ] = value; } } } } return target; }; $.widget.bridge = function( name, object ) { var fullName = object.prototype.widgetFullName || name; $.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string"; var args = widgetSlice.call( arguments, 1 ); var returnValue = this; if ( isMethodCall ) { // If this is an empty collection, we need to have the instance method // return undefined instead of the jQuery instance if ( !this.length && options === "instance" ) { returnValue = undefined; } else { this.each( function() { var methodValue; var instance = $.data( this, fullName ); if ( options === "instance" ) { returnValue = instance; return false; } if ( !instance ) { return $.error( "cannot call methods on " + name + " prior to initialization; " + "attempted to call method '" + options + "'" ); } if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { return $.error( "no such method '" + options + "' for " + name + " widget instance" ); } methodValue = instance[ options ].apply( instance, args ); if ( methodValue !== instance && methodValue !== undefined ) { returnValue = methodValue && methodValue.jquery ? returnValue.pushStack( methodValue.get() ) : methodValue; return false; } } ); } } else { // Allow multiple hashes to be passed on init if ( args.length ) { options = $.widget.extend.apply( null, [ options ].concat( args ) ); } this.each( function() { var instance = $.data( this, fullName ); if ( instance ) { instance.option( options || {} ); if ( instance._init ) { instance._init(); } } else { $.data( this, fullName, new object( options, this ) ); } } ); } return returnValue; }; }; $.Widget = function( /* options, element */ ) {}; $.Widget._childConstructors = []; $.Widget.prototype = { widgetName: "widget", widgetEventPrefix: "", defaultElement: "
", options: { classes: {}, disabled: false, // Callbacks create: null }, _createWidget: function( options, element ) { element = $( element || this.defaultElement || this )[ 0 ]; this.element = $( element ); this.uuid = widgetUuid++; this.eventNamespace = "." + this.widgetName + this.uuid; this.bindings = $(); this.hoverable = $(); this.focusable = $(); this.classesElementLookup = {}; if ( element !== this ) { $.data( element, this.widgetFullName, this ); this._on( true, this.element, { remove: function( event ) { if ( event.target === element ) { this.destroy(); } } } ); this.document = $( element.style ? // Element within the document element.ownerDocument : // Element is window or document element.document || element ); this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); } this.options = $.widget.extend( {}, this.options, this._getCreateOptions(), options ); this._create(); if ( this.options.disabled ) { this._setOptionDisabled( this.options.disabled ); } this._trigger( "create", null, this._getCreateEventData() ); this._init(); }, _getCreateOptions: function() { return {}; }, _getCreateEventData: $.noop, _create: $.noop, _init: $.noop, destroy: function() { var that = this; this._destroy(); $.each( this.classesElementLookup, function( key, value ) { that._removeClass( value, key ); } ); // We can probably remove the unbind calls in 2.0 // all event bindings should go through this._on() this.element .off( this.eventNamespace ) .removeData( this.widgetFullName ); this.widget() .off( this.eventNamespace ) .removeAttr( "aria-disabled" ); // Clean up events and states this.bindings.off( this.eventNamespace ); }, _destroy: $.noop, widget: function() { return this.element; }, option: function( key, value ) { var options = key; var parts; var curOption; var i; if ( arguments.length === 0 ) { // Don't return a reference to the internal hash return $.widget.extend( {}, this.options ); } if ( typeof key === "string" ) { // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } options = {}; parts = key.split( "." ); key = parts.shift(); if ( parts.length ) { curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); for ( i = 0; i < parts.length - 1; i++ ) { curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; curOption = curOption[ parts[ i ] ]; } key = parts.pop(); if ( arguments.length === 1 ) { return curOption[ key ] === undefined ? null : curOption[ key ]; } curOption[ key ] = value; } else { if ( arguments.length === 1 ) { return this.options[ key ] === undefined ? null : this.options[ key ]; } options[ key ] = value; } } this._setOptions( options ); return this; }, _setOptions: function( options ) { var key; for ( key in options ) { this._setOption( key, options[ key ] ); } return this; }, _setOption: function( key, value ) { if ( key === "classes" ) { this._setOptionClasses( value ); } this.options[ key ] = value; if ( key === "disabled" ) { this._setOptionDisabled( value ); } return this; }, _setOptionClasses: function( value ) { var classKey, elements, currentElements; for ( classKey in value ) { currentElements = this.classesElementLookup[ classKey ]; if ( value[ classKey ] === this.options.classes[ classKey ] || !currentElements || !currentElements.length ) { continue; } // We are doing this to create a new jQuery object because the _removeClass() call // on the next line is going to destroy the reference to the current elements being // tracked. We need to save a copy of this collection so that we can add the new classes // below. elements = $( currentElements.get() ); this._removeClass( currentElements, classKey ); // We don't use _addClass() here, because that uses this.options.classes // for generating the string of classes. We want to use the value passed in from // _setOption(), this is the new value of the classes option which was passed to // _setOption(). We pass this value directly to _classes(). elements.addClass( this._classes( { element: elements, keys: classKey, classes: value, add: true } ) ); } }, _setOptionDisabled: function( value ) { this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); // If the widget is becoming disabled, then nothing is interactive if ( value ) { this._removeClass( this.hoverable, null, "ui-state-hover" ); this._removeClass( this.focusable, null, "ui-state-focus" ); } }, enable: function() { return this._setOptions( { disabled: false } ); }, disable: function() { return this._setOptions( { disabled: true } ); }, _classes: function( options ) { var full = []; var that = this; options = $.extend( { element: this.element, classes: this.options.classes || {} }, options ); function processClassString( classes, checkOption ) { var current, i; for ( i = 0; i < classes.length; i++ ) { current = that.classesElementLookup[ classes[ i ] ] || $(); if ( options.add ) { current = $( $.unique( current.get().concat( options.element.get() ) ) ); } else { current = $( current.not( options.element ).get() ); } that.classesElementLookup[ classes[ i ] ] = current; full.push( classes[ i ] ); if ( checkOption && options.classes[ classes[ i ] ] ) { full.push( options.classes[ classes[ i ] ] ); } } } this._on( options.element, { "remove": "_untrackClassesElement" } ); if ( options.keys ) { processClassString( options.keys.match( /\S+/g ) || [], true ); } if ( options.extra ) { processClassString( options.extra.match( /\S+/g ) || [] ); } return full.join( " " ); }, _untrackClassesElement: function( event ) { var that = this; $.each( that.classesElementLookup, function( key, value ) { if ( $.inArray( event.target, value ) !== -1 ) { that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); } } ); }, _removeClass: function( element, keys, extra ) { return this._toggleClass( element, keys, extra, false ); }, _addClass: function( element, keys, extra ) { return this._toggleClass( element, keys, extra, true ); }, _toggleClass: function( element, keys, extra, add ) { add = ( typeof add === "boolean" ) ? add : extra; var shift = ( typeof element === "string" || element === null ), options = { extra: shift ? keys : extra, keys: shift ? element : keys, element: shift ? this.element : element, add: add }; options.element.toggleClass( this._classes( options ), add ); return this; }, _on: function( suppressDisabledCheck, element, handlers ) { var delegateElement; var instance = this; // No suppressDisabledCheck flag, shuffle arguments if ( typeof suppressDisabledCheck !== "boolean" ) { handlers = element; element = suppressDisabledCheck; suppressDisabledCheck = false; } // No element argument, shuffle and use this.element if ( !handlers ) { handlers = element; element = this.element; delegateElement = this.widget(); } else { element = delegateElement = $( element ); this.bindings = this.bindings.add( element ); } $.each( handlers, function( event, handler ) { function handlerProxy() { // Allow widgets to customize the disabled handling // - disabled as an array instead of boolean // - disabled class as method for disabling individual parts if ( !suppressDisabledCheck && ( instance.options.disabled === true || $( this ).hasClass( "ui-state-disabled" ) ) ) { return; } return ( typeof handler === "string" ? instance[ handler ] : handler ) .apply( instance, arguments ); } // Copy the guid so direct unbinding works if ( typeof handler !== "string" ) { handlerProxy.guid = handler.guid = handler.guid || handlerProxy.guid || $.guid++; } var match = event.match( /^([\w:-]*)\s*(.*)$/ ); var eventName = match[ 1 ] + instance.eventNamespace; var selector = match[ 2 ]; if ( selector ) { delegateElement.on( eventName, selector, handlerProxy ); } else { element.on( eventName, handlerProxy ); } } ); }, _off: function( element, eventName ) { eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; element.off( eventName ).off( eventName ); // Clear the stack to avoid memory leaks (#10056) this.bindings = $( this.bindings.not( element ).get() ); this.focusable = $( this.focusable.not( element ).get() ); this.hoverable = $( this.hoverable.not( element ).get() ); }, _delay: function( handler, delay ) { function handlerProxy() { return ( typeof handler === "string" ? instance[ handler ] : handler ) .apply( instance, arguments ); } var instance = this; return setTimeout( handlerProxy, delay || 0 ); }, _hoverable: function( element ) { this.hoverable = this.hoverable.add( element ); this._on( element, { mouseenter: function( event ) { this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); }, mouseleave: function( event ) { this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); } } ); }, _focusable: function( element ) { this.focusable = this.focusable.add( element ); this._on( element, { focusin: function( event ) { this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); }, focusout: function( event ) { this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); } } ); }, _trigger: function( type, event, data ) { var prop, orig; var callback = this.options[ type ]; data = data || {}; event = $.Event( event ); event.type = ( type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type ).toLowerCase(); // The original event may come from any element // so we need to reset the target on the new event event.target = this.element[ 0 ]; // Copy original event properties over to the new event orig = event.originalEvent; if ( orig ) { for ( prop in orig ) { if ( !( prop in event ) ) { event[ prop ] = orig[ prop ]; } } } this.element.trigger( event, data ); return !( $.isFunction( callback ) && callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || event.isDefaultPrevented() ); } }; $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { if ( typeof options === "string" ) { options = { effect: options }; } var hasOptions; var effectName = !options ? method : options === true || typeof options === "number" ? defaultEffect : options.effect || defaultEffect; options = options || {}; if ( typeof options === "number" ) { options = { duration: options }; } hasOptions = !$.isEmptyObject( options ); options.complete = callback; if ( options.delay ) { element.delay( options.delay ); } if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { element[ method ]( options ); } else if ( effectName !== method && element[ effectName ] ) { element[ effectName ]( options.duration, options.easing, callback ); } else { element.queue( function( next ) { $( this )[ method ](); if ( callback ) { callback.call( element[ 0 ] ); } next(); } ); } }; } ); var widget = $.widget; /*! * jQuery UI Position 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * * http://api.jqueryui.com/position/ */ //>>label: Position //>>group: Core //>>description: Positions elements relative to other elements. //>>docs: http://api.jqueryui.com/position/ //>>demos: http://jqueryui.com/position/ ( function() { var cachedScrollbarWidth, max = Math.max, abs = Math.abs, rhorizontal = /left|center|right/, rvertical = /top|center|bottom/, roffset = /[\+\-]\d+(\.[\d]+)?%?/, rposition = /^\w+/, rpercent = /%$/, _position = $.fn.position; function getOffsets( offsets, width, height ) { return [ parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) ]; } function parseCss( element, property ) { return parseInt( $.css( element, property ), 10 ) || 0; } function getDimensions( elem ) { var raw = elem[ 0 ]; if ( raw.nodeType === 9 ) { return { width: elem.width(), height: elem.height(), offset: { top: 0, left: 0 } }; } if ( $.isWindow( raw ) ) { return { width: elem.width(), height: elem.height(), offset: { top: elem.scrollTop(), left: elem.scrollLeft() } }; } if ( raw.preventDefault ) { return { width: 0, height: 0, offset: { top: raw.pageY, left: raw.pageX } }; } return { width: elem.outerWidth(), height: elem.outerHeight(), offset: elem.offset() }; } $.position = { scrollbarWidth: function() { if ( cachedScrollbarWidth !== undefined ) { return cachedScrollbarWidth; } var w1, w2, div = $( "
" + "
" ), innerDiv = div.children()[ 0 ]; $( "body" ).append( div ); w1 = innerDiv.offsetWidth; div.css( "overflow", "scroll" ); w2 = innerDiv.offsetWidth; if ( w1 === w2 ) { w2 = div[ 0 ].clientWidth; } div.remove(); return ( cachedScrollbarWidth = w1 - w2 ); }, getScrollInfo: function( within ) { var overflowX = within.isWindow || within.isDocument ? "" : within.element.css( "overflow-x" ), overflowY = within.isWindow || within.isDocument ? "" : within.element.css( "overflow-y" ), hasOverflowX = overflowX === "scroll" || ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), hasOverflowY = overflowY === "scroll" || ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); return { width: hasOverflowY ? $.position.scrollbarWidth() : 0, height: hasOverflowX ? $.position.scrollbarWidth() : 0 }; }, getWithinInfo: function( element ) { var withinElement = $( element || window ), isWindow = $.isWindow( withinElement[ 0 ] ), isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, hasOffset = !isWindow && !isDocument; return { element: withinElement, isWindow: isWindow, isDocument: isDocument, offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, scrollLeft: withinElement.scrollLeft(), scrollTop: withinElement.scrollTop(), width: withinElement.outerWidth(), height: withinElement.outerHeight() }; } }; $.fn.position = function( options ) { if ( !options || !options.of ) { return _position.apply( this, arguments ); } // Make a copy, we don't want to modify arguments options = $.extend( {}, options ); var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, target = $( options.of ), within = $.position.getWithinInfo( options.within ), scrollInfo = $.position.getScrollInfo( within ), collision = ( options.collision || "flip" ).split( " " ), offsets = {}; dimensions = getDimensions( target ); if ( target[ 0 ].preventDefault ) { // Force left top to allow flipping options.at = "left top"; } targetWidth = dimensions.width; targetHeight = dimensions.height; targetOffset = dimensions.offset; // Clone to reuse original targetOffset later basePosition = $.extend( {}, targetOffset ); // Force my and at to have valid horizontal and vertical positions // if a value is missing or invalid, it will be converted to center $.each( [ "my", "at" ], function() { var pos = ( options[ this ] || "" ).split( " " ), horizontalOffset, verticalOffset; if ( pos.length === 1 ) { pos = rhorizontal.test( pos[ 0 ] ) ? pos.concat( [ "center" ] ) : rvertical.test( pos[ 0 ] ) ? [ "center" ].concat( pos ) : [ "center", "center" ]; } pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; // Calculate offsets horizontalOffset = roffset.exec( pos[ 0 ] ); verticalOffset = roffset.exec( pos[ 1 ] ); offsets[ this ] = [ horizontalOffset ? horizontalOffset[ 0 ] : 0, verticalOffset ? verticalOffset[ 0 ] : 0 ]; // Reduce to just the positions without the offsets options[ this ] = [ rposition.exec( pos[ 0 ] )[ 0 ], rposition.exec( pos[ 1 ] )[ 0 ] ]; } ); // Normalize collision option if ( collision.length === 1 ) { collision[ 1 ] = collision[ 0 ]; } if ( options.at[ 0 ] === "right" ) { basePosition.left += targetWidth; } else if ( options.at[ 0 ] === "center" ) { basePosition.left += targetWidth / 2; } if ( options.at[ 1 ] === "bottom" ) { basePosition.top += targetHeight; } else if ( options.at[ 1 ] === "center" ) { basePosition.top += targetHeight / 2; } atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); basePosition.left += atOffset[ 0 ]; basePosition.top += atOffset[ 1 ]; return this.each( function() { var collisionPosition, using, elem = $( this ), elemWidth = elem.outerWidth(), elemHeight = elem.outerHeight(), marginLeft = parseCss( this, "marginLeft" ), marginTop = parseCss( this, "marginTop" ), collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, position = $.extend( {}, basePosition ), myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); if ( options.my[ 0 ] === "right" ) { position.left -= elemWidth; } else if ( options.my[ 0 ] === "center" ) { position.left -= elemWidth / 2; } if ( options.my[ 1 ] === "bottom" ) { position.top -= elemHeight; } else if ( options.my[ 1 ] === "center" ) { position.top -= elemHeight / 2; } position.left += myOffset[ 0 ]; position.top += myOffset[ 1 ]; collisionPosition = { marginLeft: marginLeft, marginTop: marginTop }; $.each( [ "left", "top" ], function( i, dir ) { if ( $.ui.position[ collision[ i ] ] ) { $.ui.position[ collision[ i ] ][ dir ]( position, { targetWidth: targetWidth, targetHeight: targetHeight, elemWidth: elemWidth, elemHeight: elemHeight, collisionPosition: collisionPosition, collisionWidth: collisionWidth, collisionHeight: collisionHeight, offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], my: options.my, at: options.at, within: within, elem: elem } ); } } ); if ( options.using ) { // Adds feedback as second argument to using callback, if present using = function( props ) { var left = targetOffset.left - position.left, right = left + targetWidth - elemWidth, top = targetOffset.top - position.top, bottom = top + targetHeight - elemHeight, feedback = { target: { element: target, left: targetOffset.left, top: targetOffset.top, width: targetWidth, height: targetHeight }, element: { element: elem, left: position.left, top: position.top, width: elemWidth, height: elemHeight }, horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" }; if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { feedback.horizontal = "center"; } if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { feedback.vertical = "middle"; } if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { feedback.important = "horizontal"; } else { feedback.important = "vertical"; } options.using.call( this, props, feedback ); }; } elem.offset( $.extend( position, { using: using } ) ); } ); }; $.ui.position = { fit: { left: function( position, data ) { var within = data.within, withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, outerWidth = within.width, collisionPosLeft = position.left - data.collisionPosition.marginLeft, overLeft = withinOffset - collisionPosLeft, overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, newOverRight; // Element is wider than within if ( data.collisionWidth > outerWidth ) { // Element is initially over the left side of within if ( overLeft > 0 && overRight <= 0 ) { newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; position.left += overLeft - newOverRight; // Element is initially over right side of within } else if ( overRight > 0 && overLeft <= 0 ) { position.left = withinOffset; // Element is initially over both left and right sides of within } else { if ( overLeft > overRight ) { position.left = withinOffset + outerWidth - data.collisionWidth; } else { position.left = withinOffset; } } // Too far left -> align with left edge } else if ( overLeft > 0 ) { position.left += overLeft; // Too far right -> align with right edge } else if ( overRight > 0 ) { position.left -= overRight; // Adjust based on position and margin } else { position.left = max( position.left - collisionPosLeft, position.left ); } }, top: function( position, data ) { var within = data.within, withinOffset = within.isWindow ? within.scrollTop : within.offset.top, outerHeight = data.within.height, collisionPosTop = position.top - data.collisionPosition.marginTop, overTop = withinOffset - collisionPosTop, overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, newOverBottom; // Element is taller than within if ( data.collisionHeight > outerHeight ) { // Element is initially over the top of within if ( overTop > 0 && overBottom <= 0 ) { newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; position.top += overTop - newOverBottom; // Element is initially over bottom of within } else if ( overBottom > 0 && overTop <= 0 ) { position.top = withinOffset; // Element is initially over both top and bottom of within } else { if ( overTop > overBottom ) { position.top = withinOffset + outerHeight - data.collisionHeight; } else { position.top = withinOffset; } } // Too far up -> align with top } else if ( overTop > 0 ) { position.top += overTop; // Too far down -> align with bottom edge } else if ( overBottom > 0 ) { position.top -= overBottom; // Adjust based on position and margin } else { position.top = max( position.top - collisionPosTop, position.top ); } } }, flip: { left: function( position, data ) { var within = data.within, withinOffset = within.offset.left + within.scrollLeft, outerWidth = within.width, offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, collisionPosLeft = position.left - data.collisionPosition.marginLeft, overLeft = collisionPosLeft - offsetLeft, overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, myOffset = data.my[ 0 ] === "left" ? -data.elemWidth : data.my[ 0 ] === "right" ? data.elemWidth : 0, atOffset = data.at[ 0 ] === "left" ? data.targetWidth : data.at[ 0 ] === "right" ? -data.targetWidth : 0, offset = -2 * data.offset[ 0 ], newOverRight, newOverLeft; if ( overLeft < 0 ) { newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { position.left += myOffset + atOffset + offset; } } else if ( overRight > 0 ) { newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { position.left += myOffset + atOffset + offset; } } }, top: function( position, data ) { var within = data.within, withinOffset = within.offset.top + within.scrollTop, outerHeight = within.height, offsetTop = within.isWindow ? within.scrollTop : within.offset.top, collisionPosTop = position.top - data.collisionPosition.marginTop, overTop = collisionPosTop - offsetTop, overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, top = data.my[ 1 ] === "top", myOffset = top ? -data.elemHeight : data.my[ 1 ] === "bottom" ? data.elemHeight : 0, atOffset = data.at[ 1 ] === "top" ? data.targetHeight : data.at[ 1 ] === "bottom" ? -data.targetHeight : 0, offset = -2 * data.offset[ 1 ], newOverTop, newOverBottom; if ( overTop < 0 ) { newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { position.top += myOffset + atOffset + offset; } } else if ( overBottom > 0 ) { newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { position.top += myOffset + atOffset + offset; } } } }, flipfit: { left: function() { $.ui.position.flip.left.apply( this, arguments ); $.ui.position.fit.left.apply( this, arguments ); }, top: function() { $.ui.position.flip.top.apply( this, arguments ); $.ui.position.fit.top.apply( this, arguments ); } } }; } )(); var position = $.ui.position; /*! * jQuery UI :data 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: :data Selector //>>group: Core //>>description: Selects elements which have data stored under the specified key. //>>docs: http://api.jqueryui.com/data-selector/ var data = $.extend( $.expr[ ":" ], { data: $.expr.createPseudo ? $.expr.createPseudo( function( dataName ) { return function( elem ) { return !!$.data( elem, dataName ); }; } ) : // Support: jQuery <1.8 function( elem, i, match ) { return !!$.data( elem, match[ 3 ] ); } } ); /*! * jQuery UI Disable Selection 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: disableSelection //>>group: Core //>>description: Disable selection of text content within the set of matched elements. //>>docs: http://api.jqueryui.com/disableSelection/ // This file is deprecated var disableSelection = $.fn.extend( { disableSelection: ( function() { var eventType = "onselectstart" in document.createElement( "div" ) ? "selectstart" : "mousedown"; return function() { return this.on( eventType + ".ui-disableSelection", function( event ) { event.preventDefault(); } ); }; } )(), enableSelection: function() { return this.off( ".ui-disableSelection" ); } } ); /*! * jQuery UI Effects 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Effects Core //>>group: Effects // jscs:disable maximumLineLength //>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects. // jscs:enable maximumLineLength //>>docs: http://api.jqueryui.com/category/effects-core/ //>>demos: http://jqueryui.com/effect/ var dataSpace = "ui-effects-", dataSpaceStyle = "ui-effects-style", dataSpaceAnimated = "ui-effects-animated", // Create a local jQuery because jQuery Color relies on it and the // global may not exist with AMD and a custom build (#10199) jQuery = $; $.effects = { effect: {} }; /*! * jQuery Color Animations v2.1.2 * https://github.com/jquery/jquery-color * * Copyright 2014 jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * * Date: Wed Jan 16 08:47:09 2013 -0600 */ ( function( jQuery, undefined ) { var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " + "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", // Plusequals test for += 100 -= 100 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, // A set of RE's that can match strings and generate color tuples. stringParsers = [ { re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, parse: function( execResult ) { return [ execResult[ 1 ], execResult[ 2 ], execResult[ 3 ], execResult[ 4 ] ]; } }, { re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, parse: function( execResult ) { return [ execResult[ 1 ] * 2.55, execResult[ 2 ] * 2.55, execResult[ 3 ] * 2.55, execResult[ 4 ] ]; } }, { // This regex ignores A-F because it's compared against an already lowercased string re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, parse: function( execResult ) { return [ parseInt( execResult[ 1 ], 16 ), parseInt( execResult[ 2 ], 16 ), parseInt( execResult[ 3 ], 16 ) ]; } }, { // This regex ignores A-F because it's compared against an already lowercased string re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, parse: function( execResult ) { return [ parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) ]; } }, { re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, space: "hsla", parse: function( execResult ) { return [ execResult[ 1 ], execResult[ 2 ] / 100, execResult[ 3 ] / 100, execResult[ 4 ] ]; } } ], // JQuery.Color( ) color = jQuery.Color = function( color, green, blue, alpha ) { return new jQuery.Color.fn.parse( color, green, blue, alpha ); }, spaces = { rgba: { props: { red: { idx: 0, type: "byte" }, green: { idx: 1, type: "byte" }, blue: { idx: 2, type: "byte" } } }, hsla: { props: { hue: { idx: 0, type: "degrees" }, saturation: { idx: 1, type: "percent" }, lightness: { idx: 2, type: "percent" } } } }, propTypes = { "byte": { floor: true, max: 255 }, "percent": { max: 1 }, "degrees": { mod: 360, floor: true } }, support = color.support = {}, // Element for support tests supportElem = jQuery( "

" )[ 0 ], // Colors = jQuery.Color.names colors, // Local aliases of functions called often each = jQuery.each; // Determine rgba support immediately supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; // Define cache name and alpha properties // for rgba and hsla spaces each( spaces, function( spaceName, space ) { space.cache = "_" + spaceName; space.props.alpha = { idx: 3, type: "percent", def: 1 }; } ); function clamp( value, prop, allowEmpty ) { var type = propTypes[ prop.type ] || {}; if ( value == null ) { return ( allowEmpty || !prop.def ) ? null : prop.def; } // ~~ is an short way of doing floor for positive numbers value = type.floor ? ~~value : parseFloat( value ); // IE will pass in empty strings as value for alpha, // which will hit this case if ( isNaN( value ) ) { return prop.def; } if ( type.mod ) { // We add mod before modding to make sure that negatives values // get converted properly: -10 -> 350 return ( value + type.mod ) % type.mod; } // For now all property types without mod have min and max return 0 > value ? 0 : type.max < value ? type.max : value; } function stringParse( string ) { var inst = color(), rgba = inst._rgba = []; string = string.toLowerCase(); each( stringParsers, function( i, parser ) { var parsed, match = parser.re.exec( string ), values = match && parser.parse( match ), spaceName = parser.space || "rgba"; if ( values ) { parsed = inst[ spaceName ]( values ); // If this was an rgba parse the assignment might happen twice // oh well.... inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; rgba = inst._rgba = parsed._rgba; // Exit each( stringParsers ) here because we matched return false; } } ); // Found a stringParser that handled it if ( rgba.length ) { // If this came from a parsed string, force "transparent" when alpha is 0 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) if ( rgba.join() === "0,0,0,0" ) { jQuery.extend( rgba, colors.transparent ); } return inst; } // Named colors return colors[ string ]; } color.fn = jQuery.extend( color.prototype, { parse: function( red, green, blue, alpha ) { if ( red === undefined ) { this._rgba = [ null, null, null, null ]; return this; } if ( red.jquery || red.nodeType ) { red = jQuery( red ).css( green ); green = undefined; } var inst = this, type = jQuery.type( red ), rgba = this._rgba = []; // More than 1 argument specified - assume ( red, green, blue, alpha ) if ( green !== undefined ) { red = [ red, green, blue, alpha ]; type = "array"; } if ( type === "string" ) { return this.parse( stringParse( red ) || colors._default ); } if ( type === "array" ) { each( spaces.rgba.props, function( key, prop ) { rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); } ); return this; } if ( type === "object" ) { if ( red instanceof color ) { each( spaces, function( spaceName, space ) { if ( red[ space.cache ] ) { inst[ space.cache ] = red[ space.cache ].slice(); } } ); } else { each( spaces, function( spaceName, space ) { var cache = space.cache; each( space.props, function( key, prop ) { // If the cache doesn't exist, and we know how to convert if ( !inst[ cache ] && space.to ) { // If the value was null, we don't need to copy it // if the key was alpha, we don't need to copy it either if ( key === "alpha" || red[ key ] == null ) { return; } inst[ cache ] = space.to( inst._rgba ); } // This is the only case where we allow nulls for ALL properties. // call clamp with alwaysAllowEmpty inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); } ); // Everything defined but alpha? if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { // Use the default of 1 inst[ cache ][ 3 ] = 1; if ( space.from ) { inst._rgba = space.from( inst[ cache ] ); } } } ); } return this; } }, is: function( compare ) { var is = color( compare ), same = true, inst = this; each( spaces, function( _, space ) { var localCache, isCache = is[ space.cache ]; if ( isCache ) { localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; each( space.props, function( _, prop ) { if ( isCache[ prop.idx ] != null ) { same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); return same; } } ); } return same; } ); return same; }, _space: function() { var used = [], inst = this; each( spaces, function( spaceName, space ) { if ( inst[ space.cache ] ) { used.push( spaceName ); } } ); return used.pop(); }, transition: function( other, distance ) { var end = color( other ), spaceName = end._space(), space = spaces[ spaceName ], startColor = this.alpha() === 0 ? color( "transparent" ) : this, start = startColor[ space.cache ] || space.to( startColor._rgba ), result = start.slice(); end = end[ space.cache ]; each( space.props, function( key, prop ) { var index = prop.idx, startValue = start[ index ], endValue = end[ index ], type = propTypes[ prop.type ] || {}; // If null, don't override start value if ( endValue === null ) { return; } // If null - use end if ( startValue === null ) { result[ index ] = endValue; } else { if ( type.mod ) { if ( endValue - startValue > type.mod / 2 ) { startValue += type.mod; } else if ( startValue - endValue > type.mod / 2 ) { startValue -= type.mod; } } result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); } } ); return this[ spaceName ]( result ); }, blend: function( opaque ) { // If we are already opaque - return ourself if ( this._rgba[ 3 ] === 1 ) { return this; } var rgb = this._rgba.slice(), a = rgb.pop(), blend = color( opaque )._rgba; return color( jQuery.map( rgb, function( v, i ) { return ( 1 - a ) * blend[ i ] + a * v; } ) ); }, toRgbaString: function() { var prefix = "rgba(", rgba = jQuery.map( this._rgba, function( v, i ) { return v == null ? ( i > 2 ? 1 : 0 ) : v; } ); if ( rgba[ 3 ] === 1 ) { rgba.pop(); prefix = "rgb("; } return prefix + rgba.join() + ")"; }, toHslaString: function() { var prefix = "hsla(", hsla = jQuery.map( this.hsla(), function( v, i ) { if ( v == null ) { v = i > 2 ? 1 : 0; } // Catch 1 and 2 if ( i && i < 3 ) { v = Math.round( v * 100 ) + "%"; } return v; } ); if ( hsla[ 3 ] === 1 ) { hsla.pop(); prefix = "hsl("; } return prefix + hsla.join() + ")"; }, toHexString: function( includeAlpha ) { var rgba = this._rgba.slice(), alpha = rgba.pop(); if ( includeAlpha ) { rgba.push( ~~( alpha * 255 ) ); } return "#" + jQuery.map( rgba, function( v ) { // Default to 0 when nulls exist v = ( v || 0 ).toString( 16 ); return v.length === 1 ? "0" + v : v; } ).join( "" ); }, toString: function() { return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); } } ); color.fn.parse.prototype = color.fn; // Hsla conversions adapted from: // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 function hue2rgb( p, q, h ) { h = ( h + 1 ) % 1; if ( h * 6 < 1 ) { return p + ( q - p ) * h * 6; } if ( h * 2 < 1 ) { return q; } if ( h * 3 < 2 ) { return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; } return p; } spaces.hsla.to = function( rgba ) { if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { return [ null, null, null, rgba[ 3 ] ]; } var r = rgba[ 0 ] / 255, g = rgba[ 1 ] / 255, b = rgba[ 2 ] / 255, a = rgba[ 3 ], max = Math.max( r, g, b ), min = Math.min( r, g, b ), diff = max - min, add = max + min, l = add * 0.5, h, s; if ( min === max ) { h = 0; } else if ( r === max ) { h = ( 60 * ( g - b ) / diff ) + 360; } else if ( g === max ) { h = ( 60 * ( b - r ) / diff ) + 120; } else { h = ( 60 * ( r - g ) / diff ) + 240; } // Chroma (diff) == 0 means greyscale which, by definition, saturation = 0% // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) if ( diff === 0 ) { s = 0; } else if ( l <= 0.5 ) { s = diff / add; } else { s = diff / ( 2 - add ); } return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ]; }; spaces.hsla.from = function( hsla ) { if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { return [ null, null, null, hsla[ 3 ] ]; } var h = hsla[ 0 ] / 360, s = hsla[ 1 ], l = hsla[ 2 ], a = hsla[ 3 ], q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, p = 2 * l - q; return [ Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), Math.round( hue2rgb( p, q, h ) * 255 ), Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), a ]; }; each( spaces, function( spaceName, space ) { var props = space.props, cache = space.cache, to = space.to, from = space.from; // Makes rgba() and hsla() color.fn[ spaceName ] = function( value ) { // Generate a cache for this space if it doesn't exist if ( to && !this[ cache ] ) { this[ cache ] = to( this._rgba ); } if ( value === undefined ) { return this[ cache ].slice(); } var ret, type = jQuery.type( value ), arr = ( type === "array" || type === "object" ) ? value : arguments, local = this[ cache ].slice(); each( props, function( key, prop ) { var val = arr[ type === "object" ? key : prop.idx ]; if ( val == null ) { val = local[ prop.idx ]; } local[ prop.idx ] = clamp( val, prop ); } ); if ( from ) { ret = color( from( local ) ); ret[ cache ] = local; return ret; } else { return color( local ); } }; // Makes red() green() blue() alpha() hue() saturation() lightness() each( props, function( key, prop ) { // Alpha is included in more than one space if ( color.fn[ key ] ) { return; } color.fn[ key ] = function( value ) { var vtype = jQuery.type( value ), fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), local = this[ fn ](), cur = local[ prop.idx ], match; if ( vtype === "undefined" ) { return cur; } if ( vtype === "function" ) { value = value.call( this, cur ); vtype = jQuery.type( value ); } if ( value == null && prop.empty ) { return this; } if ( vtype === "string" ) { match = rplusequals.exec( value ); if ( match ) { value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); } } local[ prop.idx ] = value; return this[ fn ]( local ); }; } ); } ); // Add cssHook and .fx.step function for each named hook. // accept a space separated string of properties color.hook = function( hook ) { var hooks = hook.split( " " ); each( hooks, function( i, hook ) { jQuery.cssHooks[ hook ] = { set: function( elem, value ) { var parsed, curElem, backgroundColor = ""; if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { value = color( parsed || value ); if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { curElem = hook === "backgroundColor" ? elem.parentNode : elem; while ( ( backgroundColor === "" || backgroundColor === "transparent" ) && curElem && curElem.style ) { try { backgroundColor = jQuery.css( curElem, "backgroundColor" ); curElem = curElem.parentNode; } catch ( e ) { } } value = value.blend( backgroundColor && backgroundColor !== "transparent" ? backgroundColor : "_default" ); } value = value.toRgbaString(); } try { elem.style[ hook ] = value; } catch ( e ) { // Wrapped to prevent IE from throwing errors on "invalid" values like // 'auto' or 'inherit' } } }; jQuery.fx.step[ hook ] = function( fx ) { if ( !fx.colorInit ) { fx.start = color( fx.elem, hook ); fx.end = color( fx.end ); fx.colorInit = true; } jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); }; } ); }; color.hook( stepHooks ); jQuery.cssHooks.borderColor = { expand: function( value ) { var expanded = {}; each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { expanded[ "border" + part + "Color" ] = value; } ); return expanded; } }; // Basic color names only. // Usage of any of the other color names requires adding yourself or including // jquery.color.svg-names.js. colors = jQuery.Color.names = { // 4.1. Basic color keywords aqua: "#00ffff", black: "#000000", blue: "#0000ff", fuchsia: "#ff00ff", gray: "#808080", green: "#008000", lime: "#00ff00", maroon: "#800000", navy: "#000080", olive: "#808000", purple: "#800080", red: "#ff0000", silver: "#c0c0c0", teal: "#008080", white: "#ffffff", yellow: "#ffff00", // 4.2.3. "transparent" color keyword transparent: [ null, null, null, 0 ], _default: "#ffffff" }; } )( jQuery ); /******************************************************************************/ /****************************** CLASS ANIMATIONS ******************************/ /******************************************************************************/ ( function() { var classAnimationActions = [ "add", "remove", "toggle" ], shorthandStyles = { border: 1, borderBottom: 1, borderColor: 1, borderLeft: 1, borderRight: 1, borderTop: 1, borderWidth: 1, margin: 1, padding: 1 }; $.each( [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { $.fx.step[ prop ] = function( fx ) { if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { jQuery.style( fx.elem, prop, fx.end ); fx.setAttr = true; } }; } ); function getElementStyles( elem ) { var key, len, style = elem.ownerDocument.defaultView ? elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : elem.currentStyle, styles = {}; if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { len = style.length; while ( len-- ) { key = style[ len ]; if ( typeof style[ key ] === "string" ) { styles[ $.camelCase( key ) ] = style[ key ]; } } // Support: Opera, IE <9 } else { for ( key in style ) { if ( typeof style[ key ] === "string" ) { styles[ key ] = style[ key ]; } } } return styles; } function styleDifference( oldStyle, newStyle ) { var diff = {}, name, value; for ( name in newStyle ) { value = newStyle[ name ]; if ( oldStyle[ name ] !== value ) { if ( !shorthandStyles[ name ] ) { if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { diff[ name ] = value; } } } } return diff; } // Support: jQuery <1.8 if ( !$.fn.addBack ) { $.fn.addBack = function( selector ) { return this.add( selector == null ? this.prevObject : this.prevObject.filter( selector ) ); }; } $.effects.animateClass = function( value, duration, easing, callback ) { var o = $.speed( duration, easing, callback ); return this.queue( function() { var animated = $( this ), baseClass = animated.attr( "class" ) || "", applyClassChange, allAnimations = o.children ? animated.find( "*" ).addBack() : animated; // Map the animated objects to store the original styles. allAnimations = allAnimations.map( function() { var el = $( this ); return { el: el, start: getElementStyles( this ) }; } ); // Apply class change applyClassChange = function() { $.each( classAnimationActions, function( i, action ) { if ( value[ action ] ) { animated[ action + "Class" ]( value[ action ] ); } } ); }; applyClassChange(); // Map all animated objects again - calculate new styles and diff allAnimations = allAnimations.map( function() { this.end = getElementStyles( this.el[ 0 ] ); this.diff = styleDifference( this.start, this.end ); return this; } ); // Apply original class animated.attr( "class", baseClass ); // Map all animated objects again - this time collecting a promise allAnimations = allAnimations.map( function() { var styleInfo = this, dfd = $.Deferred(), opts = $.extend( {}, o, { queue: false, complete: function() { dfd.resolve( styleInfo ); } } ); this.el.animate( this.diff, opts ); return dfd.promise(); } ); // Once all animations have completed: $.when.apply( $, allAnimations.get() ).done( function() { // Set the final class applyClassChange(); // For each animated element, // clear all css properties that were animated $.each( arguments, function() { var el = this.el; $.each( this.diff, function( key ) { el.css( key, "" ); } ); } ); // This is guarnteed to be there if you use jQuery.speed() // it also handles dequeuing the next anim... o.complete.call( animated[ 0 ] ); } ); } ); }; $.fn.extend( { addClass: ( function( orig ) { return function( classNames, speed, easing, callback ) { return speed ? $.effects.animateClass.call( this, { add: classNames }, speed, easing, callback ) : orig.apply( this, arguments ); }; } )( $.fn.addClass ), removeClass: ( function( orig ) { return function( classNames, speed, easing, callback ) { return arguments.length > 1 ? $.effects.animateClass.call( this, { remove: classNames }, speed, easing, callback ) : orig.apply( this, arguments ); }; } )( $.fn.removeClass ), toggleClass: ( function( orig ) { return function( classNames, force, speed, easing, callback ) { if ( typeof force === "boolean" || force === undefined ) { if ( !speed ) { // Without speed parameter return orig.apply( this, arguments ); } else { return $.effects.animateClass.call( this, ( force ? { add: classNames } : { remove: classNames } ), speed, easing, callback ); } } else { // Without force parameter return $.effects.animateClass.call( this, { toggle: classNames }, force, speed, easing ); } }; } )( $.fn.toggleClass ), switchClass: function( remove, add, speed, easing, callback ) { return $.effects.animateClass.call( this, { add: add, remove: remove }, speed, easing, callback ); } } ); } )(); /******************************************************************************/ /*********************************** EFFECTS **********************************/ /******************************************************************************/ ( function() { if ( $.expr && $.expr.filters && $.expr.filters.animated ) { $.expr.filters.animated = ( function( orig ) { return function( elem ) { return !!$( elem ).data( dataSpaceAnimated ) || orig( elem ); }; } )( $.expr.filters.animated ); } if ( $.uiBackCompat !== false ) { $.extend( $.effects, { // Saves a set of properties in a data storage save: function( element, set ) { var i = 0, length = set.length; for ( ; i < length; i++ ) { if ( set[ i ] !== null ) { element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); } } }, // Restores a set of previously saved properties from a data storage restore: function( element, set ) { var val, i = 0, length = set.length; for ( ; i < length; i++ ) { if ( set[ i ] !== null ) { val = element.data( dataSpace + set[ i ] ); element.css( set[ i ], val ); } } }, setMode: function( el, mode ) { if ( mode === "toggle" ) { mode = el.is( ":hidden" ) ? "show" : "hide"; } return mode; }, // Wraps the element around a wrapper that copies position properties createWrapper: function( element ) { // If the element is already wrapped, return it if ( element.parent().is( ".ui-effects-wrapper" ) ) { return element.parent(); } // Wrap the element var props = { width: element.outerWidth( true ), height: element.outerHeight( true ), "float": element.css( "float" ) }, wrapper = $( "

" ) .addClass( "ui-effects-wrapper" ) .css( { fontSize: "100%", background: "transparent", border: "none", margin: 0, padding: 0 } ), // Store the size in case width/height are defined in % - Fixes #5245 size = { width: element.width(), height: element.height() }, active = document.activeElement; // Support: Firefox // Firefox incorrectly exposes anonymous content // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 try { active.id; } catch ( e ) { active = document.body; } element.wrap( wrapper ); // Fixes #7595 - Elements lose focus when wrapped. if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { $( active ).trigger( "focus" ); } // Hotfix for jQuery 1.4 since some change in wrap() seems to actually // lose the reference to the wrapped element wrapper = element.parent(); // Transfer positioning properties to the wrapper if ( element.css( "position" ) === "static" ) { wrapper.css( { position: "relative" } ); element.css( { position: "relative" } ); } else { $.extend( props, { position: element.css( "position" ), zIndex: element.css( "z-index" ) } ); $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) { props[ pos ] = element.css( pos ); if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { props[ pos ] = "auto"; } } ); element.css( { position: "relative", top: 0, left: 0, right: "auto", bottom: "auto" } ); } element.css( size ); return wrapper.css( props ).show(); }, removeWrapper: function( element ) { var active = document.activeElement; if ( element.parent().is( ".ui-effects-wrapper" ) ) { element.parent().replaceWith( element ); // Fixes #7595 - Elements lose focus when wrapped. if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { $( active ).trigger( "focus" ); } } return element; } } ); } $.extend( $.effects, { version: "1.12.1", define: function( name, mode, effect ) { if ( !effect ) { effect = mode; mode = "effect"; } $.effects.effect[ name ] = effect; $.effects.effect[ name ].mode = mode; return effect; }, scaledDimensions: function( element, percent, direction ) { if ( percent === 0 ) { return { height: 0, width: 0, outerHeight: 0, outerWidth: 0 }; } var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1, y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1; return { height: element.height() * y, width: element.width() * x, outerHeight: element.outerHeight() * y, outerWidth: element.outerWidth() * x }; }, clipToBox: function( animation ) { return { width: animation.clip.right - animation.clip.left, height: animation.clip.bottom - animation.clip.top, left: animation.clip.left, top: animation.clip.top }; }, // Injects recently queued functions to be first in line (after "inprogress") unshift: function( element, queueLength, count ) { var queue = element.queue(); if ( queueLength > 1 ) { queue.splice.apply( queue, [ 1, 0 ].concat( queue.splice( queueLength, count ) ) ); } element.dequeue(); }, saveStyle: function( element ) { element.data( dataSpaceStyle, element[ 0 ].style.cssText ); }, restoreStyle: function( element ) { element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || ""; element.removeData( dataSpaceStyle ); }, mode: function( element, mode ) { var hidden = element.is( ":hidden" ); if ( mode === "toggle" ) { mode = hidden ? "show" : "hide"; } if ( hidden ? mode === "hide" : mode === "show" ) { mode = "none"; } return mode; }, // Translates a [top,left] array into a baseline value getBaseline: function( origin, original ) { var y, x; switch ( origin[ 0 ] ) { case "top": y = 0; break; case "middle": y = 0.5; break; case "bottom": y = 1; break; default: y = origin[ 0 ] / original.height; } switch ( origin[ 1 ] ) { case "left": x = 0; break; case "center": x = 0.5; break; case "right": x = 1; break; default: x = origin[ 1 ] / original.width; } return { x: x, y: y }; }, // Creates a placeholder element so that the original element can be made absolute createPlaceholder: function( element ) { var placeholder, cssPosition = element.css( "position" ), position = element.position(); // Lock in margins first to account for form elements, which // will change margin if you explicitly set height // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380 // Support: Safari element.css( { marginTop: element.css( "marginTop" ), marginBottom: element.css( "marginBottom" ), marginLeft: element.css( "marginLeft" ), marginRight: element.css( "marginRight" ) } ) .outerWidth( element.outerWidth() ) .outerHeight( element.outerHeight() ); if ( /^(static|relative)/.test( cssPosition ) ) { cssPosition = "absolute"; placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( { // Convert inline to inline block to account for inline elements // that turn to inline block based on content (like img) display: /^(inline|ruby)/.test( element.css( "display" ) ) ? "inline-block" : "block", visibility: "hidden", // Margins need to be set to account for margin collapse marginTop: element.css( "marginTop" ), marginBottom: element.css( "marginBottom" ), marginLeft: element.css( "marginLeft" ), marginRight: element.css( "marginRight" ), "float": element.css( "float" ) } ) .outerWidth( element.outerWidth() ) .outerHeight( element.outerHeight() ) .addClass( "ui-effects-placeholder" ); element.data( dataSpace + "placeholder", placeholder ); } element.css( { position: cssPosition, left: position.left, top: position.top } ); return placeholder; }, removePlaceholder: function( element ) { var dataKey = dataSpace + "placeholder", placeholder = element.data( dataKey ); if ( placeholder ) { placeholder.remove(); element.removeData( dataKey ); } }, // Removes a placeholder if it exists and restores // properties that were modified during placeholder creation cleanUp: function( element ) { $.effects.restoreStyle( element ); $.effects.removePlaceholder( element ); }, setTransition: function( element, list, factor, value ) { value = value || {}; $.each( list, function( i, x ) { var unit = element.cssUnit( x ); if ( unit[ 0 ] > 0 ) { value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; } } ); return value; } } ); // Return an effect options object for the given parameters: function _normalizeArguments( effect, options, speed, callback ) { // Allow passing all options as the first parameter if ( $.isPlainObject( effect ) ) { options = effect; effect = effect.effect; } // Convert to an object effect = { effect: effect }; // Catch (effect, null, ...) if ( options == null ) { options = {}; } // Catch (effect, callback) if ( $.isFunction( options ) ) { callback = options; speed = null; options = {}; } // Catch (effect, speed, ?) if ( typeof options === "number" || $.fx.speeds[ options ] ) { callback = speed; speed = options; options = {}; } // Catch (effect, options, callback) if ( $.isFunction( speed ) ) { callback = speed; speed = null; } // Add options to effect if ( options ) { $.extend( effect, options ); } speed = speed || options.duration; effect.duration = $.fx.off ? 0 : typeof speed === "number" ? speed : speed in $.fx.speeds ? $.fx.speeds[ speed ] : $.fx.speeds._default; effect.complete = callback || options.complete; return effect; } function standardAnimationOption( option ) { // Valid standard speeds (nothing, number, named speed) if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { return true; } // Invalid strings - treat as "normal" speed if ( typeof option === "string" && !$.effects.effect[ option ] ) { return true; } // Complete callback if ( $.isFunction( option ) ) { return true; } // Options hash (but not naming an effect) if ( typeof option === "object" && !option.effect ) { return true; } // Didn't match any standard API return false; } $.fn.extend( { effect: function( /* effect, options, speed, callback */ ) { var args = _normalizeArguments.apply( this, arguments ), effectMethod = $.effects.effect[ args.effect ], defaultMode = effectMethod.mode, queue = args.queue, queueName = queue || "fx", complete = args.complete, mode = args.mode, modes = [], prefilter = function( next ) { var el = $( this ), normalizedMode = $.effects.mode( el, mode ) || defaultMode; // Sentinel for duck-punching the :animated psuedo-selector el.data( dataSpaceAnimated, true ); // Save effect mode for later use, // we can't just call $.effects.mode again later, // as the .show() below destroys the initial state modes.push( normalizedMode ); // See $.uiBackCompat inside of run() for removal of defaultMode in 1.13 if ( defaultMode && ( normalizedMode === "show" || ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) { el.show(); } if ( !defaultMode || normalizedMode !== "none" ) { $.effects.saveStyle( el ); } if ( $.isFunction( next ) ) { next(); } }; if ( $.fx.off || !effectMethod ) { // Delegate to the original method (e.g., .show()) if possible if ( mode ) { return this[ mode ]( args.duration, complete ); } else { return this.each( function() { if ( complete ) { complete.call( this ); } } ); } } function run( next ) { var elem = $( this ); function cleanup() { elem.removeData( dataSpaceAnimated ); $.effects.cleanUp( elem ); if ( args.mode === "hide" ) { elem.hide(); } done(); } function done() { if ( $.isFunction( complete ) ) { complete.call( elem[ 0 ] ); } if ( $.isFunction( next ) ) { next(); } } // Override mode option on a per element basis, // as toggle can be either show or hide depending on element state args.mode = modes.shift(); if ( $.uiBackCompat !== false && !defaultMode ) { if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { // Call the core method to track "olddisplay" properly elem[ mode ](); done(); } else { effectMethod.call( elem[ 0 ], args, done ); } } else { if ( args.mode === "none" ) { // Call the core method to track "olddisplay" properly elem[ mode ](); done(); } else { effectMethod.call( elem[ 0 ], args, cleanup ); } } } // Run prefilter on all elements first to ensure that // any showing or hiding happens before placeholder creation, // which ensures that any layout changes are correctly captured. return queue === false ? this.each( prefilter ).each( run ) : this.queue( queueName, prefilter ).queue( queueName, run ); }, show: ( function( orig ) { return function( option ) { if ( standardAnimationOption( option ) ) { return orig.apply( this, arguments ); } else { var args = _normalizeArguments.apply( this, arguments ); args.mode = "show"; return this.effect.call( this, args ); } }; } )( $.fn.show ), hide: ( function( orig ) { return function( option ) { if ( standardAnimationOption( option ) ) { return orig.apply( this, arguments ); } else { var args = _normalizeArguments.apply( this, arguments ); args.mode = "hide"; return this.effect.call( this, args ); } }; } )( $.fn.hide ), toggle: ( function( orig ) { return function( option ) { if ( standardAnimationOption( option ) || typeof option === "boolean" ) { return orig.apply( this, arguments ); } else { var args = _normalizeArguments.apply( this, arguments ); args.mode = "toggle"; return this.effect.call( this, args ); } }; } )( $.fn.toggle ), cssUnit: function( key ) { var style = this.css( key ), val = []; $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { if ( style.indexOf( unit ) > 0 ) { val = [ parseFloat( style ), unit ]; } } ); return val; }, cssClip: function( clipObj ) { if ( clipObj ) { return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " + clipObj.bottom + "px " + clipObj.left + "px)" ); } return parseClip( this.css( "clip" ), this ); }, transfer: function( options, done ) { var element = $( this ), target = $( options.to ), targetFixed = target.css( "position" ) === "fixed", body = $( "body" ), fixTop = targetFixed ? body.scrollTop() : 0, fixLeft = targetFixed ? body.scrollLeft() : 0, endPosition = target.offset(), animation = { top: endPosition.top - fixTop, left: endPosition.left - fixLeft, height: target.innerHeight(), width: target.innerWidth() }, startPosition = element.offset(), transfer = $( "
" ) .appendTo( "body" ) .addClass( options.className ) .css( { top: startPosition.top - fixTop, left: startPosition.left - fixLeft, height: element.innerHeight(), width: element.innerWidth(), position: targetFixed ? "fixed" : "absolute" } ) .animate( animation, options.duration, options.easing, function() { transfer.remove(); if ( $.isFunction( done ) ) { done(); } } ); } } ); function parseClip( str, element ) { var outerWidth = element.outerWidth(), outerHeight = element.outerHeight(), clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/, values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ]; return { top: parseFloat( values[ 1 ] ) || 0, right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ), bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ), left: parseFloat( values[ 4 ] ) || 0 }; } $.fx.step.clip = function( fx ) { if ( !fx.clipInit ) { fx.start = $( fx.elem ).cssClip(); if ( typeof fx.end === "string" ) { fx.end = parseClip( fx.end, fx.elem ); } fx.clipInit = true; } $( fx.elem ).cssClip( { top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top, right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right, bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom, left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left } ); }; } )(); /******************************************************************************/ /*********************************** EASING ***********************************/ /******************************************************************************/ ( function() { // Based on easing equations from Robert Penner (http://www.robertpenner.com/easing) var baseEasings = {}; $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { baseEasings[ name ] = function( p ) { return Math.pow( p, i + 2 ); }; } ); $.extend( baseEasings, { Sine: function( p ) { return 1 - Math.cos( p * Math.PI / 2 ); }, Circ: function( p ) { return 1 - Math.sqrt( 1 - p * p ); }, Elastic: function( p ) { return p === 0 || p === 1 ? p : -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 ); }, Back: function( p ) { return p * p * ( 3 * p - 2 ); }, Bounce: function( p ) { var pow2, bounce = 4; while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); } } ); $.each( baseEasings, function( name, easeIn ) { $.easing[ "easeIn" + name ] = easeIn; $.easing[ "easeOut" + name ] = function( p ) { return 1 - easeIn( 1 - p ); }; $.easing[ "easeInOut" + name ] = function( p ) { return p < 0.5 ? easeIn( p * 2 ) / 2 : 1 - easeIn( p * -2 + 2 ) / 2; }; } ); } )(); var effect = $.effects; /*! * jQuery UI Effects Blind 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Blind Effect //>>group: Effects //>>description: Blinds the element. //>>docs: http://api.jqueryui.com/blind-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) { var map = { up: [ "bottom", "top" ], vertical: [ "bottom", "top" ], down: [ "top", "bottom" ], left: [ "right", "left" ], horizontal: [ "right", "left" ], right: [ "left", "right" ] }, element = $( this ), direction = options.direction || "up", start = element.cssClip(), animate = { clip: $.extend( {}, start ) }, placeholder = $.effects.createPlaceholder( element ); animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ]; if ( options.mode === "show" ) { element.cssClip( animate.clip ); if ( placeholder ) { placeholder.css( $.effects.clipToBox( animate ) ); } animate.clip = start; } if ( placeholder ) { placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing ); } element.animate( animate, { queue: false, duration: options.duration, easing: options.easing, complete: done } ); } ); /*! * jQuery UI Effects Bounce 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Bounce Effect //>>group: Effects //>>description: Bounces an element horizontally or vertically n times. //>>docs: http://api.jqueryui.com/bounce-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) { var upAnim, downAnim, refValue, element = $( this ), // Defaults: mode = options.mode, hide = mode === "hide", show = mode === "show", direction = options.direction || "up", distance = options.distance, times = options.times || 5, // Number of internal animations anims = times * 2 + ( show || hide ? 1 : 0 ), speed = options.duration / anims, easing = options.easing, // Utility: ref = ( direction === "up" || direction === "down" ) ? "top" : "left", motion = ( direction === "up" || direction === "left" ), i = 0, queuelen = element.queue().length; $.effects.createPlaceholder( element ); refValue = element.css( ref ); // Default distance for the BIGGEST bounce is the outer Distance / 3 if ( !distance ) { distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; } if ( show ) { downAnim = { opacity: 1 }; downAnim[ ref ] = refValue; // If we are showing, force opacity 0 and set the initial position // then do the "first" animation element .css( "opacity", 0 ) .css( ref, motion ? -distance * 2 : distance * 2 ) .animate( downAnim, speed, easing ); } // Start at the smallest distance if we are hiding if ( hide ) { distance = distance / Math.pow( 2, times - 1 ); } downAnim = {}; downAnim[ ref ] = refValue; // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here for ( ; i < times; i++ ) { upAnim = {}; upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; element .animate( upAnim, speed, easing ) .animate( downAnim, speed, easing ); distance = hide ? distance * 2 : distance / 2; } // Last Bounce when Hiding if ( hide ) { upAnim = { opacity: 0 }; upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; element.animate( upAnim, speed, easing ); } element.queue( done ); $.effects.unshift( element, queuelen, anims + 1 ); } ); /*! * jQuery UI Effects Clip 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Clip Effect //>>group: Effects //>>description: Clips the element on and off like an old TV. //>>docs: http://api.jqueryui.com/clip-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) { var start, animate = {}, element = $( this ), direction = options.direction || "vertical", both = direction === "both", horizontal = both || direction === "horizontal", vertical = both || direction === "vertical"; start = element.cssClip(); animate.clip = { top: vertical ? ( start.bottom - start.top ) / 2 : start.top, right: horizontal ? ( start.right - start.left ) / 2 : start.right, bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom, left: horizontal ? ( start.right - start.left ) / 2 : start.left }; $.effects.createPlaceholder( element ); if ( options.mode === "show" ) { element.cssClip( animate.clip ); animate.clip = start; } element.animate( animate, { queue: false, duration: options.duration, easing: options.easing, complete: done } ); } ); /*! * jQuery UI Effects Drop 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Drop Effect //>>group: Effects //>>description: Moves an element in one direction and hides it at the same time. //>>docs: http://api.jqueryui.com/drop-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) { var distance, element = $( this ), mode = options.mode, show = mode === "show", direction = options.direction || "left", ref = ( direction === "up" || direction === "down" ) ? "top" : "left", motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=", oppositeMotion = ( motion === "+=" ) ? "-=" : "+=", animation = { opacity: 0 }; $.effects.createPlaceholder( element ); distance = options.distance || element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2; animation[ ref ] = motion + distance; if ( show ) { element.css( animation ); animation[ ref ] = oppositeMotion + distance; animation.opacity = 1; } // Animate element.animate( animation, { queue: false, duration: options.duration, easing: options.easing, complete: done } ); } ); /*! * jQuery UI Effects Explode 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Explode Effect //>>group: Effects // jscs:disable maximumLineLength //>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness. // jscs:enable maximumLineLength //>>docs: http://api.jqueryui.com/explode-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) { var i, j, left, top, mx, my, rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3, cells = rows, element = $( this ), mode = options.mode, show = mode === "show", // Show and then visibility:hidden the element before calculating offset offset = element.show().css( "visibility", "hidden" ).offset(), // Width and height of a piece width = Math.ceil( element.outerWidth() / cells ), height = Math.ceil( element.outerHeight() / rows ), pieces = []; // Children animate complete: function childComplete() { pieces.push( this ); if ( pieces.length === rows * cells ) { animComplete(); } } // Clone the element for each row and cell. for ( i = 0; i < rows; i++ ) { // ===> top = offset.top + i * height; my = i - ( rows - 1 ) / 2; for ( j = 0; j < cells; j++ ) { // ||| left = offset.left + j * width; mx = j - ( cells - 1 ) / 2; // Create a clone of the now hidden main element that will be absolute positioned // within a wrapper div off the -left and -top equal to size of our pieces element .clone() .appendTo( "body" ) .wrap( "
" ) .css( { position: "absolute", visibility: "visible", left: -j * width, top: -i * height } ) // Select the wrapper - make it overflow: hidden and absolute positioned based on // where the original was located +left and +top equal to the size of pieces .parent() .addClass( "ui-effects-explode" ) .css( { position: "absolute", overflow: "hidden", width: width, height: height, left: left + ( show ? mx * width : 0 ), top: top + ( show ? my * height : 0 ), opacity: show ? 0 : 1 } ) .animate( { left: left + ( show ? 0 : mx * width ), top: top + ( show ? 0 : my * height ), opacity: show ? 1 : 0 }, options.duration || 500, options.easing, childComplete ); } } function animComplete() { element.css( { visibility: "visible" } ); $( pieces ).remove(); done(); } } ); /*! * jQuery UI Effects Fade 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Fade Effect //>>group: Effects //>>description: Fades the element. //>>docs: http://api.jqueryui.com/fade-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) { var show = options.mode === "show"; $( this ) .css( "opacity", show ? 0 : 1 ) .animate( { opacity: show ? 1 : 0 }, { queue: false, duration: options.duration, easing: options.easing, complete: done } ); } ); /*! * jQuery UI Effects Fold 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Fold Effect //>>group: Effects //>>description: Folds an element first horizontally and then vertically. //>>docs: http://api.jqueryui.com/fold-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) { // Create element var element = $( this ), mode = options.mode, show = mode === "show", hide = mode === "hide", size = options.size || 15, percent = /([0-9]+)%/.exec( size ), horizFirst = !!options.horizFirst, ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ], duration = options.duration / 2, placeholder = $.effects.createPlaceholder( element ), start = element.cssClip(), animation1 = { clip: $.extend( {}, start ) }, animation2 = { clip: $.extend( {}, start ) }, distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ], queuelen = element.queue().length; if ( percent ) { size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; } animation1.clip[ ref[ 0 ] ] = size; animation2.clip[ ref[ 0 ] ] = size; animation2.clip[ ref[ 1 ] ] = 0; if ( show ) { element.cssClip( animation2.clip ); if ( placeholder ) { placeholder.css( $.effects.clipToBox( animation2 ) ); } animation2.clip = start; } // Animate element .queue( function( next ) { if ( placeholder ) { placeholder .animate( $.effects.clipToBox( animation1 ), duration, options.easing ) .animate( $.effects.clipToBox( animation2 ), duration, options.easing ); } next(); } ) .animate( animation1, duration, options.easing ) .animate( animation2, duration, options.easing ) .queue( done ); $.effects.unshift( element, queuelen, 4 ); } ); /*! * jQuery UI Effects Highlight 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Highlight Effect //>>group: Effects //>>description: Highlights the background of an element in a defined color for a custom duration. //>>docs: http://api.jqueryui.com/highlight-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) { var element = $( this ), animation = { backgroundColor: element.css( "backgroundColor" ) }; if ( options.mode === "hide" ) { animation.opacity = 0; } $.effects.saveStyle( element ); element .css( { backgroundImage: "none", backgroundColor: options.color || "#ffff99" } ) .animate( animation, { queue: false, duration: options.duration, easing: options.easing, complete: done } ); } ); /*! * jQuery UI Effects Size 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Size Effect //>>group: Effects //>>description: Resize an element to a specified width and height. //>>docs: http://api.jqueryui.com/size-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectSize = $.effects.define( "size", function( options, done ) { // Create element var baseline, factor, temp, element = $( this ), // Copy for children cProps = [ "fontSize" ], vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], // Set options mode = options.mode, restore = mode !== "effect", scale = options.scale || "both", origin = options.origin || [ "middle", "center" ], position = element.css( "position" ), pos = element.position(), original = $.effects.scaledDimensions( element ), from = options.from || original, to = options.to || $.effects.scaledDimensions( element, 0 ); $.effects.createPlaceholder( element ); if ( mode === "show" ) { temp = from; from = to; to = temp; } // Set scaling factor factor = { from: { y: from.height / original.height, x: from.width / original.width }, to: { y: to.height / original.height, x: to.width / original.width } }; // Scale the css box if ( scale === "box" || scale === "both" ) { // Vertical props scaling if ( factor.from.y !== factor.to.y ) { from = $.effects.setTransition( element, vProps, factor.from.y, from ); to = $.effects.setTransition( element, vProps, factor.to.y, to ); } // Horizontal props scaling if ( factor.from.x !== factor.to.x ) { from = $.effects.setTransition( element, hProps, factor.from.x, from ); to = $.effects.setTransition( element, hProps, factor.to.x, to ); } } // Scale the content if ( scale === "content" || scale === "both" ) { // Vertical props scaling if ( factor.from.y !== factor.to.y ) { from = $.effects.setTransition( element, cProps, factor.from.y, from ); to = $.effects.setTransition( element, cProps, factor.to.y, to ); } } // Adjust the position properties based on the provided origin points if ( origin ) { baseline = $.effects.getBaseline( origin, original ); from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top; from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left; to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top; to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left; } element.css( from ); // Animate the children if desired if ( scale === "content" || scale === "both" ) { vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps ); hProps = hProps.concat( [ "marginLeft", "marginRight" ] ); // Only animate children with width attributes specified // TODO: is this right? should we include anything with css width specified as well element.find( "*[width]" ).each( function() { var child = $( this ), childOriginal = $.effects.scaledDimensions( child ), childFrom = { height: childOriginal.height * factor.from.y, width: childOriginal.width * factor.from.x, outerHeight: childOriginal.outerHeight * factor.from.y, outerWidth: childOriginal.outerWidth * factor.from.x }, childTo = { height: childOriginal.height * factor.to.y, width: childOriginal.width * factor.to.x, outerHeight: childOriginal.height * factor.to.y, outerWidth: childOriginal.width * factor.to.x }; // Vertical props scaling if ( factor.from.y !== factor.to.y ) { childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom ); childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo ); } // Horizontal props scaling if ( factor.from.x !== factor.to.x ) { childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom ); childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo ); } if ( restore ) { $.effects.saveStyle( child ); } // Animate children child.css( childFrom ); child.animate( childTo, options.duration, options.easing, function() { // Restore children if ( restore ) { $.effects.restoreStyle( child ); } } ); } ); } // Animate element.animate( to, { queue: false, duration: options.duration, easing: options.easing, complete: function() { var offset = element.offset(); if ( to.opacity === 0 ) { element.css( "opacity", from.opacity ); } if ( !restore ) { element .css( "position", position === "static" ? "relative" : position ) .offset( offset ); // Need to save style here so that automatic style restoration // doesn't restore to the original styles from before the animation. $.effects.saveStyle( element ); } done(); } } ); } ); /*! * jQuery UI Effects Scale 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Scale Effect //>>group: Effects //>>description: Grows or shrinks an element and its content. //>>docs: http://api.jqueryui.com/scale-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectScale = $.effects.define( "scale", function( options, done ) { // Create element var el = $( this ), mode = options.mode, percent = parseInt( options.percent, 10 ) || ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ), newOptions = $.extend( true, { from: $.effects.scaledDimensions( el ), to: $.effects.scaledDimensions( el, percent, options.direction || "both" ), origin: options.origin || [ "middle", "center" ] }, options ); // Fade option to support puff if ( options.fade ) { newOptions.from.opacity = 1; newOptions.to.opacity = 0; } $.effects.effect.size.call( this, newOptions, done ); } ); /*! * jQuery UI Effects Puff 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Puff Effect //>>group: Effects //>>description: Creates a puff effect by scaling the element up and hiding it at the same time. //>>docs: http://api.jqueryui.com/puff-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) { var newOptions = $.extend( true, {}, options, { fade: true, percent: parseInt( options.percent, 10 ) || 150 } ); $.effects.effect.scale.call( this, newOptions, done ); } ); /*! * jQuery UI Effects Pulsate 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Pulsate Effect //>>group: Effects //>>description: Pulsates an element n times by changing the opacity to zero and back. //>>docs: http://api.jqueryui.com/pulsate-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) { var element = $( this ), mode = options.mode, show = mode === "show", hide = mode === "hide", showhide = show || hide, // Showing or hiding leaves off the "last" animation anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), duration = options.duration / anims, animateTo = 0, i = 1, queuelen = element.queue().length; if ( show || !element.is( ":visible" ) ) { element.css( "opacity", 0 ).show(); animateTo = 1; } // Anims - 1 opacity "toggles" for ( ; i < anims; i++ ) { element.animate( { opacity: animateTo }, duration, options.easing ); animateTo = 1 - animateTo; } element.animate( { opacity: animateTo }, duration, options.easing ); element.queue( done ); $.effects.unshift( element, queuelen, anims + 1 ); } ); /*! * jQuery UI Effects Shake 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Shake Effect //>>group: Effects //>>description: Shakes an element horizontally or vertically n times. //>>docs: http://api.jqueryui.com/shake-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectShake = $.effects.define( "shake", function( options, done ) { var i = 1, element = $( this ), direction = options.direction || "left", distance = options.distance || 20, times = options.times || 3, anims = times * 2 + 1, speed = Math.round( options.duration / anims ), ref = ( direction === "up" || direction === "down" ) ? "top" : "left", positiveMotion = ( direction === "up" || direction === "left" ), animation = {}, animation1 = {}, animation2 = {}, queuelen = element.queue().length; $.effects.createPlaceholder( element ); // Animation animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; // Animate element.animate( animation, speed, options.easing ); // Shakes for ( ; i < times; i++ ) { element .animate( animation1, speed, options.easing ) .animate( animation2, speed, options.easing ); } element .animate( animation1, speed, options.easing ) .animate( animation, speed / 2, options.easing ) .queue( done ); $.effects.unshift( element, queuelen, anims + 1 ); } ); /*! * jQuery UI Effects Slide 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Slide Effect //>>group: Effects //>>description: Slides an element in and out of the viewport. //>>docs: http://api.jqueryui.com/slide-effect/ //>>demos: http://jqueryui.com/effect/ var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) { var startClip, startRef, element = $( this ), map = { up: [ "bottom", "top" ], down: [ "top", "bottom" ], left: [ "right", "left" ], right: [ "left", "right" ] }, mode = options.mode, direction = options.direction || "left", ref = ( direction === "up" || direction === "down" ) ? "top" : "left", positiveMotion = ( direction === "up" || direction === "left" ), distance = options.distance || element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ), animation = {}; $.effects.createPlaceholder( element ); startClip = element.cssClip(); startRef = element.position()[ ref ]; // Define hide animation animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef; animation.clip = element.cssClip(); animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ]; // Reverse the animation if we're showing if ( mode === "show" ) { element.cssClip( animation.clip ); element.css( ref, animation[ ref ] ); animation.clip = startClip; animation[ ref ] = startRef; } // Actually animate element.animate( animation, { queue: false, duration: options.duration, easing: options.easing, complete: done } ); } ); /*! * jQuery UI Effects Transfer 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Transfer Effect //>>group: Effects //>>description: Displays a transfer effect from one element to another. //>>docs: http://api.jqueryui.com/transfer-effect/ //>>demos: http://jqueryui.com/effect/ var effect; if ( $.uiBackCompat !== false ) { effect = $.effects.define( "transfer", function( options, done ) { $( this ).transfer( options, done ); } ); } var effectsEffectTransfer = effect; /*! * jQuery UI Focusable 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: :focusable Selector //>>group: Core //>>description: Selects elements which can be focused. //>>docs: http://api.jqueryui.com/focusable-selector/ // Selectors $.ui.focusable = function( element, hasTabindex ) { var map, mapName, img, focusableIfVisible, fieldset, nodeName = element.nodeName.toLowerCase(); if ( "area" === nodeName ) { map = element.parentNode; mapName = map.name; if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { return false; } img = $( "img[usemap='#" + mapName + "']" ); return img.length > 0 && img.is( ":visible" ); } if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) { focusableIfVisible = !element.disabled; if ( focusableIfVisible ) { // Form controls within a disabled fieldset are disabled. // However, controls within the fieldset's legend do not get disabled. // Since controls generally aren't placed inside legends, we skip // this portion of the check. fieldset = $( element ).closest( "fieldset" )[ 0 ]; if ( fieldset ) { focusableIfVisible = !fieldset.disabled; } } } else if ( "a" === nodeName ) { focusableIfVisible = element.href || hasTabindex; } else { focusableIfVisible = hasTabindex; } return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) ); }; // Support: IE 8 only // IE 8 doesn't resolve inherit to visible/hidden for computed values function visible( element ) { var visibility = element.css( "visibility" ); while ( visibility === "inherit" ) { element = element.parent(); visibility = element.css( "visibility" ); } return visibility !== "hidden"; } $.extend( $.expr[ ":" ], { focusable: function( element ) { return $.ui.focusable( element, $.attr( element, "tabindex" ) != null ); } } ); var focusable = $.ui.focusable; // Support: IE8 Only // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop // with a string, so we need to find the proper form. var form = $.fn.form = function() { return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form ); }; /*! * jQuery UI Form Reset Mixin 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Form Reset Mixin //>>group: Core //>>description: Refresh input widgets when their form is reset //>>docs: http://api.jqueryui.com/form-reset-mixin/ var formResetMixin = $.ui.formResetMixin = { _formResetHandler: function() { var form = $( this ); // Wait for the form reset to actually happen before refreshing setTimeout( function() { var instances = form.data( "ui-form-reset-instances" ); $.each( instances, function() { this.refresh(); } ); } ); }, _bindFormResetHandler: function() { this.form = this.element.form(); if ( !this.form.length ) { return; } var instances = this.form.data( "ui-form-reset-instances" ) || []; if ( !instances.length ) { // We don't use _on() here because we use a single event handler per form this.form.on( "reset.ui-form-reset", this._formResetHandler ); } instances.push( this ); this.form.data( "ui-form-reset-instances", instances ); }, _unbindFormResetHandler: function() { if ( !this.form.length ) { return; } var instances = this.form.data( "ui-form-reset-instances" ); instances.splice( $.inArray( this, instances ), 1 ); if ( instances.length ) { this.form.data( "ui-form-reset-instances", instances ); } else { this.form .removeData( "ui-form-reset-instances" ) .off( "reset.ui-form-reset" ); } } }; /*! * jQuery UI Support for jQuery core 1.7.x 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * */ //>>label: jQuery 1.7 Support //>>group: Core //>>description: Support version 1.7.x of jQuery core // Support: jQuery 1.7 only // Not a great way to check versions, but since we only support 1.7+ and only // need to detect <1.8, this is a simple check that should suffice. Checking // for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0 // and we'll never reach 1.70.0 (if we do, we certainly won't be supporting // 1.7 anymore). See #11197 for why we're not using feature detection. if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) { // Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight() // Unlike jQuery Core 1.8+, these only support numeric values to set the // dimensions in pixels $.each( [ "Width", "Height" ], function( i, name ) { var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], type = name.toLowerCase(), orig = { innerWidth: $.fn.innerWidth, innerHeight: $.fn.innerHeight, outerWidth: $.fn.outerWidth, outerHeight: $.fn.outerHeight }; function reduce( elem, size, border, margin ) { $.each( side, function() { size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; if ( border ) { size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; } if ( margin ) { size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; } } ); return size; } $.fn[ "inner" + name ] = function( size ) { if ( size === undefined ) { return orig[ "inner" + name ].call( this ); } return this.each( function() { $( this ).css( type, reduce( this, size ) + "px" ); } ); }; $.fn[ "outer" + name ] = function( size, margin ) { if ( typeof size !== "number" ) { return orig[ "outer" + name ].call( this, size ); } return this.each( function() { $( this ).css( type, reduce( this, size, true, margin ) + "px" ); } ); }; } ); $.fn.addBack = function( selector ) { return this.add( selector == null ? this.prevObject : this.prevObject.filter( selector ) ); }; } ; /*! * jQuery UI Keycode 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Keycode //>>group: Core //>>description: Provide keycodes as keynames //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ var keycode = $.ui.keyCode = { BACKSPACE: 8, COMMA: 188, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, LEFT: 37, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SPACE: 32, TAB: 9, UP: 38 }; // Internal use only var escapeSelector = $.ui.escapeSelector = ( function() { var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g; return function( selector ) { return selector.replace( selectorEscape, "\\$1" ); }; } )(); /*! * jQuery UI Labels 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: labels //>>group: Core //>>description: Find all the labels associated with a given input //>>docs: http://api.jqueryui.com/labels/ var labels = $.fn.labels = function() { var ancestor, selector, id, labels, ancestors; // Check control.labels first if ( this[ 0 ].labels && this[ 0 ].labels.length ) { return this.pushStack( this[ 0 ].labels ); } // Support: IE <= 11, FF <= 37, Android <= 2.3 only // Above browsers do not support control.labels. Everything below is to support them // as well as document fragments. control.labels does not work on document fragments labels = this.eq( 0 ).parents( "label" ); // Look for the label based on the id id = this.attr( "id" ); if ( id ) { // We don't search against the document in case the element // is disconnected from the DOM ancestor = this.eq( 0 ).parents().last(); // Get a full set of top level ancestors ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() ); // Create a selector for the label based on the id selector = "label[for='" + $.ui.escapeSelector( id ) + "']"; labels = labels.add( ancestors.find( selector ).addBack( selector ) ); } // Return whatever we have found for labels return this.pushStack( labels ); }; /*! * jQuery UI Scroll Parent 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: scrollParent //>>group: Core //>>description: Get the closest ancestor element that is scrollable. //>>docs: http://api.jqueryui.com/scrollParent/ var scrollParent = $.fn.scrollParent = function( includeHidden ) { var position = this.css( "position" ), excludeStaticParent = position === "absolute", overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, scrollParent = this.parents().filter( function() { var parent = $( this ); if ( excludeStaticParent && parent.css( "position" ) === "static" ) { return false; } return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) ); } ).eq( 0 ); return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent; }; /*! * jQuery UI Tabbable 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: :tabbable Selector //>>group: Core //>>description: Selects elements which can be tabbed to. //>>docs: http://api.jqueryui.com/tabbable-selector/ var tabbable = $.extend( $.expr[ ":" ], { tabbable: function( element ) { var tabIndex = $.attr( element, "tabindex" ), hasTabindex = tabIndex != null; return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex ); } } ); /*! * jQuery UI Unique ID 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: uniqueId //>>group: Core //>>description: Functions to generate and remove uniqueId's //>>docs: http://api.jqueryui.com/uniqueId/ var uniqueId = $.fn.extend( { uniqueId: ( function() { var uuid = 0; return function() { return this.each( function() { if ( !this.id ) { this.id = "ui-id-" + ( ++uuid ); } } ); }; } )(), removeUniqueId: function() { return this.each( function() { if ( /^ui-id-\d+$/.test( this.id ) ) { $( this ).removeAttr( "id" ); } } ); } } ); /*! * jQuery UI Accordion 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license */ //>>label: Accordion //>>group: Widgets // jscs:disable maximumLineLength //>>description: Displays collapsible content panels for presenting information in a limited amount of space. // jscs:enable maximumLineLength //>>docs: http://api.jqueryui.com/accordion/ //>>demos: http://jqueryui.com/accordion/ //>>css.structure: ../../themes/base/core.css //>>css.structure: ../../themes/base/accordion.css //>>css.theme: ../../themes/base/theme.css var widgetsAccordion = $.widget( "ui.accordion", { version: "1.12.1", options: { active: 0, animate: {}, classes: { "ui-accordion-header": "ui-corner-top", "ui-accordion-header-collapsed": "ui-corner-all", "ui-accordion-content": "ui-corner-bottom" }, collapsible: false, event: "click", header: "> li > :first-child, > :not(li):even", heightStyle: "auto", icons: { activeHeader: "ui-icon-triangle-1-s", header: "ui-icon-triangle-1-e" }, // Callbacks activate: null, beforeActivate: null }, hideProps: { borderTopWidth: "hide", borderBottomWidth: "hide", paddingTop: "hide", paddingBottom: "hide", height: "hide" }, showProps: { borderTopWidth: "show", borderBottomWidth: "show", paddingTop: "show", paddingBottom: "show", height: "show" }, _create: function() { var options = this.options; this.prevShow = this.prevHide = $(); this._addClass( "ui-accordion", "ui-widget ui-helper-reset" ); this.element.attr( "role", "tablist" ); // Don't allow collapsible: false and active: false / null if ( !options.collapsible && ( options.active === false || options.active == null ) ) { options.active = 0; } this._processPanels(); // handle negative values if ( options.active < 0 ) { options.active += this.headers.length; } this._refresh(); }, _getCreateEventData: function() { return { header: this.active, panel: !this.active.length ? $() : this.active.next() }; }, _createIcons: function() { var icon, children, icons = this.options.icons; if ( icons ) { icon = $( "" ); this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header ); icon.prependTo( this.headers ); children = this.active.children( ".ui-accordion-header-icon" ); this._removeClass( children, icons.header ) ._addClass( children, null, icons.activeHeader ) ._addClass( this.headers, "ui-accordion-icons" ); } }, _destroyIcons: function() { this._removeClass( this.headers, "ui-accordion-icons" ); this.headers.children( ".ui-accordion-header-icon" ).remove(); }, _destroy: function() { var contents; // Clean up main element this.element.removeAttr( "role" ); // Clean up headers this.headers .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" ) .removeUniqueId(); this._destroyIcons(); // Clean up content panels contents = this.headers.next() .css( "display", "" ) .removeAttr( "role aria-hidden aria-labelledby" ) .removeUniqueId(); if ( this.options.heightStyle !== "content" ) { contents.css( "height", "" ); } }, _setOption: function( key, value ) { if ( key === "active" ) { // _activate() will handle invalid values and update this.options this._activate( value ); return; } if ( key === "event" ) { if ( this.options.event ) { this._off( this.headers, this.options.event ); } this._setupEvents( value ); } this._super( key, value ); // Setting collapsible: false while collapsed; open first panel if ( key === "collapsible" && !value && this.options.active === false ) { this._activate( 0 ); } if ( key === "icons" ) { this._destroyIcons(); if ( value ) { this._createIcons(); } } }, _setOptionDisabled: function( value ) { this._super( value ); this.element.attr( "aria-disabled", value ); // Support: IE8 Only // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE // so we need to add the disabled class to the headers and panels this._toggleClass( null, "ui-state-disabled", !!value ); this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled", !!value ); }, _keydown: function( event ) { if ( event.altKey || event.ctrlKey ) { return; } var keyCode = $.ui.keyCode, length = this.headers.length, currentIndex = this.headers.index( event.target ), toFocus = false; switch ( event.keyCode ) { case keyCode.RIGHT: case keyCode.DOWN: toFocus = this.headers[ ( currentIndex + 1 ) % length ]; break; case keyCode.LEFT: case keyCode.UP: toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; break; case keyCode.SPACE: case keyCode.ENTER: this._eventHandler( event ); break; case keyCode.HOME: toFocus = this.headers[ 0 ]; break; case keyCode.END: toFocus = this.headers[ length - 1 ]; break; } if ( toFocus ) { $( event.target ).attr( "tabIndex", -1 ); $( toFocus ).attr( "tabIndex", 0 ); $( toFocus ).trigger( "focus" ); event.preventDefault(); } }, _panelKeyDown: function( event ) { if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { $( event.currentTarget ).prev().trigger( "focus" ); } }, refresh: function() { var options = this.options; this._processPanels(); // Was collapsed or no panel if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { options.active = false; this.active = $(); // active false only when collapsible is true } else if ( options.active === false ) { this._activate( 0 ); // was active, but active panel is gone } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { // all remaining panel are disabled if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) { options.active = false; this.active = $(); // activate previous panel } else { this._activate( Math.max( 0, options.active - 1 ) ); } // was active, active panel still exists } else { // make sure active index is correct options.active = this.headers.index( this.active ); } this._destroyIcons(); this._refresh(); }, _processPanels: function() { var prevHeaders = this.headers, prevPanels = this.panels; this.headers = this.element.find( this.options.header ); this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed", "ui-state-default" ); this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide(); this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" ); // Avoid memory leaks (#10056) if ( prevPanels ) { this._off( prevHeaders.not( this.headers ) ); this._off( prevPanels.not( this.panels ) ); } }, _refresh: function() { var maxHeight, options = this.options, heightStyle = options.heightStyle, parent = this.element.parent(); this.active = this._findActive( options.active ); this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" ) ._removeClass( this.active, "ui-accordion-header-collapsed" ); this._addClass( this.active.next(), "ui-accordion-content-active" ); this.active.next().show(); this.headers .attr( "role", "tab" ) .each( function() { var header = $( this ), headerId = header.uniqueId().attr( "id" ), panel = header.next(), panelId = panel.uniqueId().attr( "id" ); header.attr( "aria-controls", panelId ); panel.attr( "aria-labelledby", headerId ); } ) .next() .attr( "role", "tabpanel" ); this.headers .not( this.active ) .attr( { "aria-selected": "false", "aria-expanded": "false", tabIndex: -1 } ) .next() .attr( { "aria-hidden": "true" } ) .hide(); // Make sure at least one header is in the tab order if ( !this.active.length ) { this.headers.eq( 0 ).attr( "tabIndex", 0 ); } else { this.active.attr( { "aria-selected": "true", "aria-expanded": "true", tabIndex: 0 } ) .next() .attr( { "aria-hidden": "false" } ); } this._createIcons(); this._setupEvents( options.event ); if ( heightStyle === "fill" ) { maxHeight = parent.height(); this.element.siblings( ":visible" ).each( function() { var elem = $( this ), position = elem.css( "position" ); if ( position === "absolute" || position === "fixed" ) { return; } maxHeight -= elem.outerHeight( true ); } ); this.headers.each( function() { maxHeight -= $( this ).outerHeight( true ); } ); this.headers.next() .each( function() { $( this ).height( Math.max( 0, maxHeight - $( this ).innerHeight() + $( this ).height() ) ); } ) .css( "overflow", "auto" ); } else if ( heightStyle === "auto" ) { maxHeight = 0; this.headers.next() .each( function() { var isVisible = $( this ).is( ":visible" ); if ( !isVisible ) { $( this ).show(); } maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); if ( !isVisible ) { $( this ).hide(); } } ) .height( maxHeight ); } }, _activate: function( index ) { var active = this._findActive( index )[ 0 ]; // Trying to activate the already active panel if ( active === this.active[ 0 ] ) { return; } // Trying to collapse, simulate a click on the currently active header active = active || this.active[ 0 ]; this._eventHandler( { target: active, currentTarget: active, preventDefault: $.noop } ); }, _findActive: function( selector ) { return typeof selector === "number" ? this.headers.eq( selector ) : $(); }, _setupEvents: function( event ) { var events = { keydown: "_keydown" }; if ( event ) { $.each( event.split( " " ), function( index, eventName ) { events[ eventName ] = "_eventHandler"; } ); } this._off( this.headers.add( this.headers.next() ) ); this._on( this.headers, events ); this._on( this.headers.next(), { keydown: "_panelKeyDown" } ); this._hoverable( this.headers ); this._focusable( this.headers ); }, _eventHandler: function( event ) { var activeChildren, clickedChildren, options = this.options, active = this.active, clicked = $( event.currentTarget ), clickedIsActive = clicked[ 0 ] === active[ 0 ], collapsing = clickedIsActive && options.collapsible, toShow = collapsing ? $() : clicked.next(), toHide = active.next(), eventData = { oldHeader: active, oldPanel: toHide, newHeader: collapsing ? $() : clicked, newPanel: toShow }; event.preventDefault(); if ( // click on active header, but not collapsible ( clickedIsActive && !options.collapsible ) || // allow canceling activation ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { return; } options.active = collapsing ? false : this.headers.index( clicked ); // When the call to ._toggle() comes after the class changes // it causes a very odd bug in IE 8 (see #6720) this.active = clickedIsActive ? $() : clicked; this._toggle( eventData ); // Switch classes // corner classes on the previously active header stay after the animation this._removeClass( active, "ui-accordion-header-active", "ui-state-active" ); if ( options.icons ) { activeChildren = active.children( ".ui-accordion-header-icon" ); this._removeClass( activeChildren, null, options.icons.activeHeader ) ._addClass( activeChildren, null, options.icons.header ); } if ( !clickedIsActive ) { this._removeClass( clicked, "ui-accordion-header-collapsed" ) ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" ); if ( options.icons ) { clickedChildren = clicked.children( ".ui-accordion-header-icon" ); this._removeClass( clickedChildren, null, options.icons.header ) ._addClass( clickedChildren, null, options.icons.activeHeader ); } this._addClass( clicked.next(), "ui-accordion-content-active" ); } }, _toggle: function( data ) { var toShow = data.newPanel, toHide = this.prevShow.length ? this.prevShow : data.oldPanel; // Handle activating a panel during the animation for another activation this.prevShow.add( this.prevHide ).stop( true, true ); this.prevShow = toShow; this.prevHide = toHide; if ( this.options.animate ) { this._animate( toShow, toHide, data ); } else { toHide.hide(); toShow.show(); this._toggleComplete( data ); } toHide.attr( { "aria-hidden": "true" } ); toHide.prev().attr( { "aria-selected": "false", "aria-expanded": "false" } ); // if we're switching panels, remove the old header from the tab order // if we're opening from collapsed state, remove the previous header from the tab order // if we're collapsing, then keep the collapsing header in the tab order if ( toShow.length && toHide.length ) { toHide.prev().attr( { "tabIndex": -1, "aria-expanded": "false" } ); } else if ( toShow.length ) { this.headers.filter( function() { return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; } ) .attr( "tabIndex", -1 ); } toShow .attr( "aria-hidden", "false" ) .prev() .attr( { "aria-selected": "true", "aria-expanded": "true", tabIndex: 0 } ); }, _animate: function( toShow, toHide, data ) { var total, easing, duration, that = this, adjust = 0, boxSizing = toShow.css( "box-sizing" ), down = toShow.length && ( !toHide.length || ( toShow.index() < toHide.index() ) ), animate = this.options.animate || {}, options = down && animate.down || animate, complete = function() { that._toggleComplete( data ); }; if ( typeof options === "number" ) { duration = options; } if ( typeof options === "string" ) { easing = options; } // fall back from options to animation in case of partial down settings easing = easing || options.easing || animate.easing; duration = duration || options.duration || animate.duration; if ( !toHide.length ) { return toShow.animate( this.showProps, duration, easing, complete ); } if ( !toShow.length ) { return toHide.animate( this.hideProps, duration, easing, complete ); } total = toShow.show().outerHeight(); toHide.animate( this.hideProps, { duration: duration, easing: easing, step: function( now, fx ) { fx.now = Math.round( now ); } } ); toShow .hide() .animate( this.showProps, { duration: duration, easing: easing, complete: complete, step: function( now, fx ) { fx.now = Math.round( now ); if ( fx.prop !== "height" ) { if ( boxSizing === "content-box" ) { adjust += fx.now; } } else if ( that.options.heightStyle !== "content" ) { fx.now = Math.round( total - toHide.outerHeight() - adjust ); adjust = 0; } } } ); }, _toggleComplete: function( data ) { var toHide = data.oldPanel, prev = toHide.prev(); this._removeClass( toHide, "ui-accordion-content-active" ); this._removeClass( prev, "ui-accordion-header-active" ) ._addClass( prev, "ui-accordion-header-collapsed" ); // Work around for rendering bug in IE (#5421) if ( toHide.length ) { toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className; } this._trigger( "activate", null, data ); } } ); var safeActiveElement = $.ui.safeActiveElement = function( document ) { var activeElement; // Support: IE 9 only // IE9 throws an "Unspecified error" accessing document.activeElement from an