Falco Nogatz

Master-Student @ uulm

Aim: Transpile CHR into JavaScript

Any application that can be written in JavaScript, will eventually be written in JavaScript.
Atwood's Law

Architecture

Components

  • Parser
  • Transpiler
  • Runtime
  • Build-System

Parser

Parse the given CHR source and create a syntax tree.

rem_long @ path(X,Y,L1) \ path(X,Y,L2) <=> L1 <= L2 | true;
path_add @ path(X,Y,L1), path(Y,Z,L2) ==> X !== Z | path(X,Z,L1+L2);

Modifications:

  • Rules end with ;
  • No logical variables
  • JavaScript operators and notation

Parsing Expression Grammar

Start
  = Program

CHRRule
  = PropagationRule
  / SimplificationRule
  / SimpagationRule

PropagationRule
  = RuleName? CHRConstraints "==>" Guard? Body {
      ...
    }

RuleName
  = identifier:Identifier "@" {
      return identifier;
    }

Runtime Components

  • Constraint
  • Constraint Store
  • Propagation History

Runtime: Constraint

var Constraint = require('chr/runtime/constraint')

var c = new Constraint('a',   1,      [ 8 ])
             //        name,  arity,  arguments

c.toString() // 'a(8)'

// some properties:
c.id         // unique
c.alive
c.activated

Runtime: Store

var Store = require('chr/runtime/store')

var store = new Store()

// some methods:
store.add(constraint)
store.kill(constraint.id)
store.lookup(name, arity)

Runtime: Propagation History

var History = require('chr/runtime/history')

var history = new History()

// some methods:
history.add(rulename, ids)
history.notIn(rule, ids)

Transpiler Demo

Source:

echo 'a(0) <=> true; a(N) ==> a(N-1);' | chrjs

Generated Program Header:

function CHR(store, history) {
  this.Store = store || new Store()
  this.History = history || new History()
  this.constraints = [ "a/1" ]
}

...

Transpiler Demo

Source:

echo 'a(0) <=> true; a(N) ==> a(N-1);' | chrjs

Generated Caller for a:

...

CHR.prototype.a = function a() {
  var arity = arguments.length
  
  var constraint = new Constraint("a", arity, arguments)
  this.Store.add(constraint)
  this["_a_"+arity+"_activate"](constraint)
}

...

Transpiler Demo

Source:

echo 'a(0) <=> true; a(N) ==> a(N-1);' | chrjs

Generated Activator for a/1:

...

CHR.prototype._a_1_activate = function (constraint) {
  this._a_1_occurence_1(constraint)
  this._a_1_occurence_2(constraint)
}

...

Transpiler Demo

Generated Occurences for a/1:

CHR.prototype._a_1_occurence_1 = function (constraint) {
  // a(0) ?
  if (constraint.args[0] !== 0) { return }
  
  var ids = [ constraint.id ]
  if (ids.every(function(id) { return Store.alive(id) })) {
    if (allDifferent(ids)) {
      if (History.notIn("__rule_2", ids)) {
        History.add("__rule_2", ids)
      
        Store.kill(ids[0])
      }
    }
  }
}
CHR.prototype._a_1_occurence_2 = function (constraint) { ... }

Usage

Transpile CHR:

echo 'a(0) <=> true; a(N) ==> a(N-1);' | chrjs > a.example.js

Usage with node.js:

var konsole = require('chr/console')
var CHR = require('./a.example.js')

konsole(CHR)  // empty store

CHR.a(5)
konsole(CHR)

Run CHR.js in the Browser