#
# OpenCogGenPythonTypes.cmake
#
# Definitions for automatically building a Python `atom_types.pyx`
# file, given a master file `atom_types.script`.
#
# Example usage:
# OPENCOG_PYTHON_ATOMTYPES(atom_types.script core_types.pyx)
#
# ===================================================================
MACRO(OPENCOG_PYTHON_SETUP SCRIPT_FILE PYTHON_FILE)
SET(PYTHON_SUPPORTED_VALUE_LIST)
IF (NOT PYTHON_FILE)
MESSAGE(FATAL_ERROR "OPENCOG_PYTHON_ATOMTYPES missing PYTHON_FILE")
ENDIF (NOT PYTHON_FILE)
MESSAGE(DEBUG "Generating Python Atom Type definitions from ${SCRIPT_FILE}.")
FILE(WRITE "${PYTHON_FILE}"
"\n"
"# DO NOT EDIT THIS FILE! This file was automatically\n"
"# generated from atom definitions in\n"
"# ${SCRIPT_FILE}\n"
"# by the macro OPENCOG_PYTHON_ATOMTYPES\n"
"#\n"
"# This file contains basic python wrappers for atom creation.\n"
"#\n"
"\n"
)
ENDMACRO()
# ------------
# Print out the python definitions. Note: We special-case Atom
# since we don't want to create a function with the same
# identifier as the Python Atom object.
MACRO(OPENCOG_PYTHON_WRITE_DEFS PYTHON_FILE)
# Args and Sigs are not "real types"; they are helpers for the dynamic
# type constructors and type signatures. Skip generating python bindings.
IF (NOT ISARG STREQUAL "ARG" AND NOT ISSIG STREQUAL "SIG")
IF (NOT TYPE_NAME STREQUAL "Atom")
# XXX This is broken in two ways. First, createValue() is
# a C++ template, and so it can't be used like this.
# Also, PYTHON_SUPPORTED_VALUE_LIST is an empty list (above)
# so this is a no-op, anyway. XXX FIXME someday, I guess
# Until then, the value ctors are hard-coded into
# opencog/cython/opencog/type_constructors.pyx
IF (ISVALUE STREQUAL "VALUE" OR ISSTREAM STREQUAL "STREAM")
LIST(FIND PYTHON_SUPPORTED_VALUE_LIST ${TYPE_NAME} _INDEX)
IF (${_INDEX} GREATER -1)
# Single arg will work as all of the value constructors
# have a single argument: either a value or a vector.
FILE(APPEND "${PYTHON_FILE}"
"def ${TYPE_NAME}(arg):\n"
" return createValue(types.${TYPE_NAME}, arg)\n"
)
ENDIF (${_INDEX} GREATER -1)
ENDIF (ISVALUE STREQUAL "VALUE" OR ISSTREAM STREQUAL "STREAM")
IF (ISNODE STREQUAL "NODE")
FILE(APPEND "${PYTHON_FILE}"
"def ${TYPE_NAME}(node_name):\n"
" return add_node(types.${TYPE_NAME}, node_name)\n"
)
# Generate short name if it differs from TYPE_NAME OR if custom name
# Skip "Type" as it conflicts with Cython's Type keyword
IF (NOT SHORT_NAME STREQUAL "" AND
NOT SHORT_NAME STREQUAL "Type" AND
(HAS_CUSTOM_NAME OR NOT SHORT_NAME STREQUAL TYPE_NAME))
FILE(APPEND "${PYTHON_FILE}"
"def ${SHORT_NAME}(node_name):\n"
" return add_node(types.${TYPE_NAME}, node_name)\n"
)
ENDIF ()
ENDIF (ISNODE STREQUAL "NODE")
IF (ISLINK STREQUAL "LINK")
FILE(APPEND "${PYTHON_FILE}"
"def ${TYPE_NAME}(*args):\n"
" return add_link(types.${TYPE_NAME}, args)\n"
)
# Generate short name if it differs from TYPE_NAME OR if custom name
IF (NOT SHORT_NAME STREQUAL "" AND
(HAS_CUSTOM_NAME OR NOT SHORT_NAME STREQUAL TYPE_NAME))
FILE(APPEND "${PYTHON_FILE}"
"def ${SHORT_NAME}(*args):\n"
" return add_link(types.${TYPE_NAME}, args)\n"
)
ENDIF ()
ENDIF (ISLINK STREQUAL "LINK")
ENDIF (NOT TYPE_NAME STREQUAL "Atom")
ENDIF (NOT ISARG STREQUAL "ARG" AND NOT ISSIG STREQUAL "SIG")
ENDMACRO(OPENCOG_PYTHON_WRITE_DEFS PYTHON_FILE)
# ------------
# Main entry point.
MACRO(OPENCOG_PYTHON_ATOMTYPES SCRIPT_FILE PYTHON_FILE)
OPENCOG_PYTHON_SETUP(${SCRIPT_FILE} ${PYTHON_FILE})
FILE(STRINGS "${SCRIPT_FILE}" TYPE_SCRIPT_CONTENTS)
FOREACH (LINE ${TYPE_SCRIPT_CONTENTS})
OPENCOG_TYPEINFO_REGEX()
IF (MATCHED AND CMAKE_MATCH_1)
OPENCOG_TYPEINFO_SETUP()
OPENCOG_PYTHON_WRITE_DEFS(${PYTHON_FILE}) # Print out python definitions
ELSEIF (NOT MATCHED)
MESSAGE(FATAL_ERROR "Invalid line in ${SCRIPT_FILE} file: [${LINE}]")
ENDIF ()
ENDFOREACH (LINE)
ENDMACRO()
#####################################################################