diff --git a/CMakeLists.txt b/CMakeLists.txt index f24bd853..c672f0f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required(VERSION 3.17) get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(is_multi_config) +if (is_multi_config) set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING - "Semicolon separated list of supported configuration types") + "Semicolon separated list of supported configuration types") mark_as_advanced(CMAKE_CONFIGURATION_TYPES) -elseif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) +elseif (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) message(WARNING "No CMAKE_BUILD_TYPE is selected") -endif() +endif () project(j) enable_language(C CXX ASM) @@ -16,9 +16,9 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) include(CTest) -if(PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) +if (PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(BUILD_SHARED_LIBS ON) -endif() +endif () set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) @@ -82,14 +82,33 @@ add_compile_options($<$:-Wno-unknown-pragmas>) add_subdirectory(jsrc) add_subdirectory(base64) + +# see https://cliutils.gitlab.io/modern-cmake/chapters/projects/submodule.html for method used to have cmake git submodule +find_package(Git REQUIRED) +if (GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") + # Update submodules as needed + option(GIT_SUBMODULE "Check submodules during build" ON) + if (GIT_SUBMODULE) + message(STATUS "Submodule update") + execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_SUBMOD_RESULT) + if (NOT GIT_SUBMOD_RESULT EQUAL "0") + message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules") + endif () + endif () +endif () +if (NOT EXISTS "${PROJECT_SOURCE_DIR}/An-Algorithm-Library/CMakeLists.txt") + message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.") +endif () add_subdirectory(An-Algorithm-Library EXCLUDE_FROM_ALL) -if(${DOCS} STREQUAL "YES") +if (${DOCS} STREQUAL "YES") add_subdirectory(docs) -endif() +endif () -if(BUILD_SHARED_LIBS) +if (BUILD_SHARED_LIBS) set_target_properties(j-base64 PROPERTIES - POSITION_INDEPENDENT_CODE ON) + POSITION_INDEPENDENT_CODE ON) add_subdirectory(test) -endif() +endif () target_link_libraries(j PRIVATE j-base64) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9711c9f9..d562f597 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ * [Ubuntu CMake update instructions](https://apt.kitware.com/) * Ninja * Additional prerequisites for building the documentation: - * python packages: sphinx, breathe, divio-docs-theme + * python packages: sphinx, breathe, myst_parser, divio-docs-theme * doxygen 2. Checkout the repository: ```sh diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake index 13823090..5979f341 100644 --- a/cmake/FindSphinx.cmake +++ b/cmake/FindSphinx.cmake @@ -1,11 +1,22 @@ -#Look for an executable called sphinx-build -find_program(SPHINX_EXECUTABLE - NAMES sphinx-build - DOC "Path to sphinx-build executable") +find_package (Python3 COMPONENTS Interpreter Development REQUIRED) + +execute_process( + COMMAND ${Python3_EXECUTABLE} "-c" "exec(\"import sphinx\\nimport os\\nprint (os.path.dirname(sphinx.__file__))\")" + RESULT_VARIABLE EXIT_CODE + OUTPUT_VARIABLE PIP3_SPHINX_DATA + OUTPUT_STRIP_TRAILING_WHITESPACE +) +message(STATUS ${Python3_EXECUTABLE}) +message(STATUS ${PIP3_SPHINX_DATA}/bin) +find_program(SPHINX_EXECUTABLE NAMES sphinx-build + HINTS ${PIP3_SPHINX_DATA} ~/.local/bin + DOC "Sphinx documentation generator" + ) include(FindPackageHandleStandardArgs) -#Handle standard arguments to find_package like REQUIRED and QUIET -find_package_handle_standard_args(Sphinx - "Failed to find sphinx-build executable" - SPHINX_EXECUTABLE) \ No newline at end of file +find_package_handle_standard_args(Sphinx DEFAULT_MSG + SPHINX_EXECUTABLE + ) + +mark_as_advanced(SPHINX_EXECUTABLE) \ No newline at end of file diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 8ffa1d34..384eda09 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,9 +1,14 @@ find_package(Doxygen REQUIRED) find_package(Sphinx REQUIRED) -# Find all the public headers +# Find all the public headers/source files get_target_property(J_PUBLIC_HEADER_DIR j INTERFACE_INCLUDE_DIRECTORIES) -file(GLOB_RECURSE J_PUBLIC_HEADERS ${J_PUBLIC_HEADER_DIR}/*.h) +file(GLOB_RECURSE J_PUBLIC_HEADERS + ${J_PUBLIC_HEADER_DIR}/*.h + ${J_PUBLIC_HEADER_DIR}/*.c + ${J_PUBLIC_HEADER_DIR}/*.hpp + ${J_PUBLIC_HEADER_DIR}/*.cpp + ) set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/jsrc) @@ -20,11 +25,11 @@ file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR}) # Only regenerate Doxygen when the Doxyfile or public headers change add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE} - DEPENDS ${J_PUBLIC_HEADERS} - COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} - MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} - COMMENT "Generating docs" - VERBATIM) + DEPENDS ${J_PUBLIC_HEADERS} + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT} + MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN} + COMMENT "Generating docs" + VERBATIM) # Nice named target so we can run the job easily add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE}) @@ -33,28 +38,29 @@ set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/source) set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx) set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html) +file(GLOB_RECURSE SPHINX_SOURCE_SOURCE_CODE + ${SPHINX_SOURCE}/*.md + ${SPHINX_SOURCE}/*.rst + ) + # Only regenerate Sphinx when: # - Doxygen has rerun # - Our doc files have been updated # - The Sphinx config has been updated add_custom_command(OUTPUT ${SPHINX_INDEX_FILE} - COMMAND - ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/preprocessor.py - --input ${SPHINX_SOURCE} - --output ${SPHINX_SOURCE}/__output__ - && - ${SPHINX_EXECUTABLE} -b html - # Tell Breathe where to find the Doxygen output - -Dbreathe_projects.jsrc=${DOXYGEN_OUTPUT_DIR}/xml - -Dbreathe_default_project=jsrc - ${SPHINX_SOURCE}/__output__ ${SPHINX_BUILD} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS - # Other docs files you want to track should go here (or in some variable) - ${CMAKE_CURRENT_SOURCE_DIR}/source/index.rst - ${DOXYGEN_INDEX_FILE} - MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py - COMMENT "Generating documentation with Sphinx") + COMMAND + ${SPHINX_EXECUTABLE} -b html + # Tell Breathe where to find the Doxygen output + -Dbreathe_projects.jsrc=${DOXYGEN_OUTPUT_DIR}/xml + -Dbreathe_default_project=jsrc + ${SPHINX_SOURCE} ${SPHINX_BUILD} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS + # Other docs files you want to track should go here (or in some variable) + ${SPHINX_SOURCE_SOURCE_CODE} + ${DOXYGEN_INDEX_FILE} + MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py + COMMENT "Generating documentation with Sphinx") # Nice named target so we can run the job easily add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE}) @@ -62,4 +68,4 @@ add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE}) # Add an install target to install the docs include(GNUInstallDirs) install(DIRECTORY ${SPHINX_BUILD} -DESTINATION ${CMAKE_INSTALL_DOCDIR}) + DESTINATION ${CMAKE_INSTALL_DOCDIR}) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index c405c4ae..ccd9edf1 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -1076,7 +1076,7 @@ IGNORE_PREFIX = # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. -GENERATE_HTML = YES +GENERATE_HTML = NO # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1620,7 +1620,7 @@ EXTRA_SEARCH_MAPPINGS = # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. -GENERATE_LATEX = YES +GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of diff --git a/docs/scripts/preprocessor.py b/docs/scripts/preprocessor.py deleted file mode 100755 index ebf58e75..00000000 --- a/docs/scripts/preprocessor.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/python3 - -""" -preprocessor for sphinx files -- reads in all .rst files in input directory -- writes processed .rst files to output directory - -by copying files to output directory, we aren't -modifying the original .rst files in any way. - -preprocessor steps: -- format tables -""" - -import argparse -import shutil -import os -import itertools - - -def find_markdown_tables(lines): - """ - return (row_start, row_end) for all markdown tables. - """ - indices = [idx for idx, line in enumerate(lines) if line.startswith("|")] - nindices = len(indices) - indices_type = ["end" if i + 1 == nindices or indices[i+1] - indices[i] > 1 - else "start" if i == 0 or indices[i] - indices[i-1] > 1 - else "mid" for i in range(nindices)] - return list(zip([indices[i] for i in range(nindices) if indices_type[i] == "start"], - [indices[i] for i in range(nindices) if indices_type[i] == "end"])) - - -def get_markdown_row_data(row): - """ - get row (or header) data from markdown row (or header) - - row - | apples | red | a | - - data - ['apples', 'red', 'a'] - """ - return [e.strip() for e in row.split("|")[1:-1]] - - -def convert_table(table, in_format="md", out_format="rst-2"): - """ - md format - | fruit | color | startswith | - | ----- | ----- | ---------- | - | apples | red | a | - | oranges | orange | o | - - rst-1 format - +---------+--------+------------+ - | fruit | color | startswith | - +=========+========+============+ - | apples | red | a | - +---------+--------+------------+ - | oranges | orange | o | - +---------+--------+------------+ - - rst-2 format - ======= ====== ========== - fruit color startswith - ======= ====== ========== - apples red a - oranges orange o - ======= ===== ========== - """ - if in_format == "md" and out_format == "rst-2": - header = get_markdown_row_data(table[0]) - rows = [get_markdown_row_data(row) for row in table[2:]] - cols = [[row[col_idx] for row in rows] - for col_idx in range(len(header))] - tbl_separator = ' '.join( - ['=' * max(len(header[col_idx]), len(max(col, key=len))) - for col_idx, col in enumerate(cols)], - ) - tbl_header = ' '.join([ - header[idx] + ' ' * (max(len(header[idx]), len(max(col, key=len))) - len(header[idx])) - for idx, col in enumerate(cols) - ]) - tbl_rows = [ - ' '.join([ - row[idx] + ' ' * (max(len(header[idx]), len(max(col, key=len))) - len(row[idx])) - for idx, col in enumerate(cols) - ]) for row in rows - ] - return [tbl_separator] + [tbl_header] + [tbl_separator] + tbl_rows + [tbl_separator] - - raise Exception("Conversion from {} to {} not implemented".format( - in_format, out_format - )) - - -def get_processed_lines(lines): - """ - replace all md tables in lines with rst-2 tables - - - additional processing can be added later if needed - """ - tpos = find_markdown_tables(lines) - - if not tpos: - return lines - - chunks = [[(0, tpos[0][0] - 1)]] + \ - [[pos] if idx == 0 - else [(tpos[idx-1][1] + 1, pos[0] - 1), pos] for idx, pos in enumerate(tpos)] + \ - [[(tpos[-1][1] + 1, len(lines) - 1)]] - - return list(itertools.chain.from_iterable([ - convert_table(lines[chunk[0]:chunk[1]+1], "md", "rst-2") if chunk in tpos \ - else lines[chunk[0]:chunk[1]+1] \ - for chunk in list(itertools.chain(*chunks)) - ])) - - -if __name__ == "__main__": - - parser = argparse.ArgumentParser() - parser.add_argument("--input", help="Input Sphinx source directory") - parser.add_argument("--output", help="Output Sphinx source directory") - args = parser.parse_args() - - shutil.rmtree(args.output, ignore_errors=True) - shutil.copytree(args.input, args.output) - - for root, dirs, files in os.walk(args.output): - for file in files: - if file.endswith('.rst'): - with open('{}/{}'.format(root, file)) as f: - data = f.read() - lines = get_processed_lines(data.splitlines()) - with open('{}/{}'.format(root, file), 'w') as f: - f.write('\n'.join(lines)) - - print("preprocessor step finished") \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index a60349a6..9e99cd8d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -23,13 +23,12 @@ copyright = '2021, Conor Hoekstra + contributors' author = 'Conor Hoekstra + contributors' - # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ "breathe" ] +extensions = ["breathe", "myst_parser"] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -46,7 +45,6 @@ # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for @@ -59,27 +57,33 @@ html_theme_path = [divio_docs_theme.get_html_theme_path()] html_theme_options = { # Options of read the docs theme - 'logo_only': False, - 'display_version': False, - 'prev_next_buttons_location': 'bottom', - 'style_external_links': True, - # Toc options - 'collapse_navigation': True, - 'sticky_navigation': False, - 'navigation_depth': 3, - 'includehidden': True, # to show also hidden TOCs in the menu bar - 'titles_only': False, + 'logo_only': False, + 'display_version': False, + 'prev_next_buttons_location': 'bottom', + 'style_external_links': True, + # Toc options + 'collapse_navigation': True, + 'sticky_navigation': False, + 'navigation_depth': 3, + 'includehidden': True, # to show also hidden TOCs in the menu bar + 'titles_only': False, # 'canonical_url': "https://docs.nitrokey.com/", # Options of Divio (divio bases on read the docs theme) - 'analytics_id' : '', - 'vcs_pageview_mode' : '', - 'show_cloud_banner' : False, #False makes the divio box disappear - 'cloud_banner_url' : '', - 'cloud_banner_markup' : '', - 'segment_id' : '' + 'analytics_id': '', + 'vcs_pageview_mode': '', + 'show_cloud_banner': False, # False makes the divio box disappear + 'cloud_banner_url': '', + 'cloud_banner_markup': '', + 'segment_id': '' } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] + +source_suffix = { + '.rst': 'restructuredtext', + # '.txt': 'markdown', + '.md': 'markdown', +} diff --git a/docs/source/verbs.rst b/docs/source/verbs-old.rst similarity index 100% rename from docs/source/verbs.rst rename to docs/source/verbs-old.rst diff --git a/docs/source/verbs.md b/docs/source/verbs.md new file mode 100644 index 00000000..533b80d6 --- /dev/null +++ b/docs/source/verbs.md @@ -0,0 +1,34 @@ + +# Verbs + +## Monadic + +### Rank + +* In APL, the equivalent expression is `≢∘⍴`. + +```{eval-rst} +.. doxygenfunction:: rank +``` + +### Tally + +* In APL, this is also known as `tally` (`≢`) [Link](https://help.dyalog.com/18.0/#Language/Primitive%20Functions/Tally.htm?Highlight=tally). +```{eval-rst} +.. doxygenfunction:: tally +``` +### Same + +* In APL, this is also known as `same`, `right tack` or `pass` (`⊢`). [Link](http://microapl.com/apl_help/ch_020_020_755.htm) +* This is more widely known as `identity` (`id` in [Haskell](https://hackage.haskell.org/package/base-4.14.1.0/docs/Prelude.html#v:id)). +```{eval-rst} +.. doxygenfunction:: same +``` +### Shape + +* In APL, this is also known as `shape` (`⍴`). [Link](http://microapl.com/apl_help/ch_020_020_460.htm). +```{eval-rst} +.. doxygenfunction:: shape +``` + +## Dyadic