#
# OpenCogGenOCamlTypes.cmake
#
# Definitions for automatically building the OCaml `atom_types.ml`
# file, given a master file `atom_types.script`.
#
# Example usage:
# OPENCOG_OCAML_ATOMTYPES(atom_types.script core_types.ml)
#
# ===================================================================
MACRO(OPENCOG_OCAML_SETUP OCAML_FILE WRAPPER_FILE HEADER_FILE)
IF (NOT OCAML_FILE)
MESSAGE(FATAL_ERROR "OPENCOG_OCAML_ATOMTYPES missing OCAML_FILE")
ENDIF (NOT OCAML_FILE)
MESSAGE(DEBUG "Generating OCaml Atom Type definitions from ${SCRIPT_FILE}.")
FILE(WRITE "${OCAML_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_OCAML_ATOMTYPES *)\n"
"\n"
"(* This file contains basic OCaml wrappers for atom creation. *)\n"
"\n"
"type atom = Atom ;; (* | Node of string | Link of atom list;; *)\n"
"\n"
"external atom_printer : atom -> string = \"atom_string_printer\" ;;\n"
"\n"
"(* We need a pretty-printer for each set of atom types *)\n"
"(* #install_printer atom_prettyprt ;; *)\n"
"let atom_prettyprt : Format.formatter -> atom -> unit =\n"
" function oport ->\n"
" fun atm -> Format.fprintf oport \"%s\" (atom_printer atm) ;;\n"
"\n"
)
FILE(WRITE "${WRAPPER_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_OCAML_ATOMTYPES\n"
"//\n"
"// This file contains basic OCaml wrappers for atom creation.\n"
"//\n"
"#define CAML_NAME_SPACE\n"
"#include <caml/memory.h>\n"
"#include <caml/mlvalues.h>\n"
"#include <opencog/ocaml/CamlWrap.h>\n"
"\n"
"#include <${HEADER_FILE}>\n"
"#include <opencog/atoms/base/Atom.h>\n"
"#include <opencog/atoms/base/Handle.h>\n"
"\n"
"using namespace opencog;\n"
"\n"
"extern \"C\" {\n"
"\n"
)
ENDMACRO()
MACRO(OPENCOG_OCAML_TEARDOWN OCAML_FILE)
FILE(APPEND "${WRAPPER_FILE}"
"} // extern \"C\"\n"
)
ENDMACRO()
# Print out the scheme definitions
MACRO(OPENCOG_OCAML_WRITE_DEFS OCAML_FILE WRAPPER_FILE)
# The function that returns the integer type of the type.
# Not needed right now, comment out.
# FILE(APPEND "${OCAML_FILE}"
# "external ${LC_SNAKE_TYPE}_atomtype : unit -> int = \"${TYPE_NAME}Type\" ;;\n"
# )
#
# FILE(APPEND "${WRAPPER_FILE}"
# "CAMLprim value ${TYPE_NAME}Type(void) {\n"
# " CAMLparam0();\n"
# " CAMLreturn(Val_long(${TYPE})); } \n"
# )
# Use short names, whenever possible. There are no backwards-compat
# issues here with the long names.
SET(ML_NAME ${LC_SNAKE_TYPE})
IF (NOT LC_SNAKE_SHORT STREQUAL "")
SET(ML_NAME ${LC_SNAKE_SHORT})
ENDIF ()
# Avoid reserved keywords
IF (ML_NAME STREQUAL "list" OR
ML_NAME STREQUAL "true" OR
ML_NAME STREQUAL "false" OR
ML_NAME STREQUAL "and" OR
ML_NAME STREQUAL "or" OR
ML_NAME STREQUAL "not" OR
ML_NAME STREQUAL "type" OR
ML_NAME STREQUAL "virtual" OR
ML_NAME STREQUAL "function"
)
SET(ML_NAME ${LC_SNAKE_TYPE})
ENDIF ()
IF (TYPE STREQUAL "NOTYPE" OR
TYPE STREQUAL "VALUATION" OR
TYPE STREQUAL "ATOM"
)
# no-op; skip
ELSEIF (ISVALUE STREQUAL "VALUE" OR ISSTREAM STREQUAL "STREAM")
FILE(APPEND "${OCAML_FILE}"
"external ${ML_NAME} : unit -> atom = \"new_${TYPE_NAME}\" ;;\n"
)
ELSEIF (ISNODE STREQUAL "NODE")
FILE(APPEND "${OCAML_FILE}"
"external ${ML_NAME} : string -> atom = \"new_${TYPE_NAME}\" ;;\n"
)
FILE(APPEND "${WRAPPER_FILE}"
"CAMLprim value new_${TYPE_NAME}(value vname) {\n"
" CAMLparam1(vname);\n"
" CAMLreturn(NewNode(vname, ${TYPE}));\n"
"}\n\n"
)
ELSEIF (ISLINK STREQUAL "LINK")
FILE(APPEND "${OCAML_FILE}"
"external ${ML_NAME} : atom list -> atom = \"new_${TYPE_NAME}\" ;;\n"
)
FILE(APPEND "${WRAPPER_FILE}"
"CAMLprim value new_${TYPE_NAME}(value vatomlist) {\n"
" CAMLparam1(vatomlist);\n"
" CAMLreturn(NewLink(vatomlist, ${TYPE}));\n"
"}\n\n"
)
ELSEIF (ISATOMSPACE STREQUAL "ATOM_SPACE")
# XXX FIXME LATER
#FILE(APPEND "${OCAML_FILE}"
# "(define-public AtomSpace cog-new-atomspace)\n"
#)
ELSEIF (ISAST STREQUAL "AST")
# XXX FIXME LATER
#FILE(APPEND "${OCAML_FILE}"
# "(define-public (${TYPE_NAME} . x)\n"
# "\t(apply cog-new-ast (cons ${TYPE_NAME}Type x)))\n"
#)
ELSE ()
MESSAGE(FATAL_ERROR "Unknown type ${TYPE}")
ENDIF ()
ENDMACRO()
# ------------
# Main entry point.
MACRO(OPENCOG_OCAML_ATOMTYPES
SCRIPT_FILE OCAML_FILE WRAPPER_FILE HEADER_FILE)
OPENCOG_OCAML_SETUP(${OCAML_FILE} ${WRAPPER_FILE} ${HEADER_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_OCAML_WRITE_DEFS(${OCAML_FILE} ${WRAPPER_FILE})
ELSEIF (NOT MATCHED)
MESSAGE(FATAL_ERROR "Invalid line in ${SCRIPT_FILE} file: [${LINE}]")
ENDIF ()
ENDFOREACH (LINE)
OPENCOG_OCAML_TEARDOWN(${OCAML_FILE})
ENDMACRO()
#####################################################################