OverviewFilesCommitsIssuesDocsReleasesPeers

knowledge-ratchet / atomspace / schema.js

139 lines · javascript ref:
/**
 * schema.js — Atom naming conventions and Scheme expression builders
 *
 * All atoms use prefixed ConceptNode names:
 *   mod:   — modules (package.json boundaries)
 *   file:  — source files (relative paths)
 *   fn:    — exported functions/classes
 *   loop:  — correction loops (by fingerprint)
 *   rule:  — learned rules (by id)
 *
 * All edges use EdgeLink + BondNode (learn-pipeline compatible):
 *   (EdgeLink (BondNode "TYPE") (ListLink SRC DST))
 *
 * Bond types:
 *   contains   — module contains file
 *   imports    — file imports from file
 *   depends-on — module depends on module
 *   exports    — file exports function/class
 *   loop-in-file  — loop involved this file
 *   resolved-by   — loop was resolved by editing this file
 *   rule-for-file — learned rule applies to this file
 */

// Escape strings for Scheme (double quotes, backslashes)
function esc (str) {
  if (!str) return ''
  return str
    .replace(/\\/g, '\\\\')
    .replace(/"/g, '\\"')
    .replace(/\n/g, '\\n')
}

// --- Node builders ---

function modNode (name) {
  return `(ConceptNode "mod:${esc(name)}")`
}

function fileNode (path) {
  return `(ConceptNode "file:${esc(path)}")`
}

function fnNode (name) {
  return `(ConceptNode "fn:${esc(name)}")`
}

function loopNode (fingerprint) {
  return `(ConceptNode "loop:${esc(fingerprint)}")`
}

function ruleNode (id) {
  return `(ConceptNode "rule:${esc(id)}")`
}

// --- Edge builder ---

function edge (bondType, src, dst) {
  return `(EdgeLink (BondNode "${esc(bondType)}") (ListLink ${src} ${dst}))`
}

// --- Value setters ---

function setStringValue (node, key, value) {
  return `(cog-set-value! ${node} (Predicate "${esc(key)}") (StringValue "${esc(value)}"))`
}

function setFloatValue (node, key, value) {
  return `(cog-set-value! ${node} (Predicate "${esc(key)}") (FloatValue ${value}))`
}

// --- Query builders ---

function meetQuery (varName, varType, body) {
  return `(cog-execute! (Meet (TypedVariable (Variable "${varName}") (Type '${varType})) (Present ${body})))`
}

// Find all files that import from a given file
function queryImporters (filePath) {
  const target = fileNode(filePath)
  return meetQuery('$consumer', 'ConceptNode',
    `(EdgeLink (BondNode "imports") (ListLink (Variable "$consumer") ${target}))`)
}

// Find all files that a given file imports from
function queryDependencies (filePath) {
  const source = fileNode(filePath)
  return meetQuery('$dep', 'ConceptNode',
    `(EdgeLink (BondNode "imports") (ListLink ${source} (Variable "$dep")))`)
}

// Find all loops involving a file
function queryLoopsForFile (filePath) {
  const target = fileNode(filePath)
  return meetQuery('$loop', 'ConceptNode',
    `(EdgeLink (BondNode "loop-in-file") (ListLink (Variable "$loop") ${target}))`)
}

// Find all rules applying to a file
function queryRulesForFile (filePath) {
  const target = fileNode(filePath)
  return meetQuery('$rule', 'ConceptNode',
    `(EdgeLink (BondNode "rule-for-file") (ListLink (Variable "$rule") ${target}))`)
}

// Find all files in a module
function queryModuleFiles (modName) {
  const mod = modNode(modName)
  return meetQuery('$file', 'ConceptNode',
    `(EdgeLink (BondNode "contains") (ListLink ${mod} (Variable "$file")))`)
}

// Get a string value from an atom
function getStringValue (node, key) {
  return `(let ((v (cog-value ${node} (Predicate "${esc(key)}")))) (if v (cog-value-ref v 0) ""))`
}

// Get a float value from an atom
function getFloatValue (node, key) {
  return `(let ((v (cog-value ${node} (Predicate "${esc(key)}")))) (if v (cog-value-ref v 0) 0))`
}

// Count atoms in AtomSpace
function reportCounts () {
  return '(cog-report-counts)'
}

module.exports = {
  esc,
  modNode, fileNode, fnNode, loopNode, ruleNode,
  edge,
  setStringValue, setFloatValue,
  meetQuery,
  queryImporters, queryDependencies,
  queryLoopsForFile, queryRulesForFile,
  queryModuleFiles,
  getStringValue, getFloatValue,
  reportCounts
}