UNPKG

chr

Version:

Interpreter for Constraint Handling Rules (CHR) in JavaScript

130 lines (112 loc) 3.86 kB
;(function () { const root = this let prevCHR if (root && root.CHR) { prevCHR = root.CHR } const Runtime = require('../runtime') const Rules = require('./rules') const Rule = require('./rule') const joinParts = require('./join-parts') let parse if (process.env.NODE_ENV === 'browserWithoutParser') { parse = root.parseCHR } else { parse = require('./parser.peg.js').parse } function CHR (opts) { opts = opts || {} opts.store = opts.store || new Runtime.Store() opts.history = opts.history || new Runtime.History() opts.rules = opts.rules || new Rules(tag) opts.scope = opts.scope || {} /** * Adds a number of rules given. */ function tag (chrSource) { let program let replacements // Examine caller format if (typeof chrSource === 'object' && chrSource.type && chrSource.type === 'Program') { // called with already parsed source code // e.g. tag({ type: 'Program', body: [ ... ] }) program = chrSource replacements = [] // allow to specify replacements as second argument if (arguments[1] && typeof arguments[1] === 'object' && arguments[1] instanceof Array) { replacements = arguments[1] } } else if (typeof chrSource === 'object' && chrSource instanceof Array && typeof chrSource[0] === 'string') { // called as template tag // e.g. tag`a ==> b` // or tag`a ==> ${ function() { console.log('Replacement test') } }` const combined = [ chrSource[0] ] Array.prototype.slice.call(arguments, 1).forEach(function (repl, ix) { combined.push(repl) combined.push(chrSource[ix + 1]) }) chrSource = joinParts(combined) replacements = Array.prototype.slice.call(arguments, 1) program = parse(chrSource) } else if (typeof chrSource === 'string' && arguments[1] && arguments[1] instanceof Array) { // called with program and replacements array // e.g. tag( // 'a ==> ${ function() { console.log("Replacement test") } }', // [ eval('( function() { console.log("Replacement test") } )') ] // ) // this is useful to ensure the scope of the given replacements program = parse(chrSource) replacements = arguments[1] } else if (typeof chrSource === 'string') { // called as normal function // e.g. tag('a ==> b') // or tag('a ==> ', function() { console.log('Replacement test') }) replacements = Array.prototype.filter.call(arguments, isFunction) chrSource = joinParts(Array.prototype.slice.call(arguments)) program = parse(chrSource) } const rules = program.body rules.forEach(function (rule) { tag.Rules.Add(rule, replacements) }) } tag.Store = opts.store tag.History = opts.history tag.Rules = opts.rules tag.Scope = opts.scope // this will save all constraint functors with // an array of the rules they occur in tag.Constraints = {} Object.defineProperty(tag, 'Functors', { get: function () { return Object.keys(tag.Constraints) } }) tag.Helper = Runtime.Helper return tag } // expose public constructors CHR.Constraint = Runtime.Constraint CHR.Store = Runtime.Store CHR.History = Runtime.History CHR.Rule = Rule CHR.version = '__VERSION__' CHR.noConflict = function () { root.CHR = prevCHR return CHR } if (typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports) { exports = module.exports = CHR } else { exports.CHR = CHR } } else { root.CHR = CHR } function isFunction (el) { return typeof el === 'function' } }).call(this)