<!DOCTYPE html>
<html>
<head>
<script data-require="jquery@1.7.2" data-semver="1.7.2" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script src="re_lib.js"></script>
<script src="prolog_js_headed.js"></script>
<script src="demo_es.js"></script>
<script type="text/javascript">
function re_finished() {
$('#finished_control_div').show();
}
function start_over() {
$('#output_div').html('');
$('#finished_control_div').hide();
$('#input_div').hide();
$('#radio_input_div').hide();
$('#control_div').show();
}
function showControlDiv() {
console.log("_dbg in showControlDiv");
$('#control_div').show();
}
function run_re() {
$('#finished_control_div').show();
var ctrl_div = document.getElementById("control_div");
ctrl_div.style.display = "none";
var output_div = document.getElementById("output_div");
output_div.style.display = "inline";
RuleEngine.reset();
var re = setup_re();
var diybio_help_term_Q = new Term('DIYBIO_HELP');
var get_diybio_help_rule_call = new Rule('get_diybio_help');
get_diybio_help_rule_call.addArg(diybio_help_term_Q);
RuleEngine.base_query = get_diybio_help_rule_call;
RuleEngine.finished_cb = re_finished;
RuleEngine.gnd_val_only = true;
RuleEngine.no_solutions_found_txt = 'Unable to determine appropriate help for your for your do it yourself biology needs, please email diybio@googlegroups.com for more assistance, thank you.';
re.fireRule(get_diybio_help_rule_call);
}
</script>
</head>
<body>
<header>
<h1>Tire Change Helper</h1>
</header>
<div id="wrap">
<div id="main-content">
<!--
<div align="center">
<div class="app_button" id="version_button">Version 0.0.1</div>
</div>
-->
<div id="output_div"></div>
<div align="center">
<div id="input_div">
<form id="input_form" method="POST" onSubmit="Util.handle_binary_input(); return false;">
<input type="radio" name="binary_input" value="yes" />
Yes <br />
<input type="radio" name="binary_input" value="no" />
No <br />
<input type="submit" id='binary_input_btn' value="Continue" onClick="Util.handle_binary_input();" />
</form>
</div>
<div id="radio_input_div">
<form id="radio_input_form" method="POST" onSubmit="Util.handle_radio_input(); return false;">
<input type="radio" name="radio_input" value="yes" />
Yes <br />
<input type="radio" name="radio_input" value="no" />
No
<input type="submit" id='radio_input_btn' value="Submit" onClick="Util.handle_radio_input();" />
</form>
</div>
</div>
<div align="center">
<div id="control_div">
<b>Welcome to the tire change helper tool.<br /> Find answers to your tire change questions in seconds.</b>
<br /><br />
<form name="control_form" method="POST" onSubmit="return false;">
<input type="submit" value="Start Tire Change Helper" onClick="run_re();" />
</form>
</div>
<div id="finished_control_div">
<a href="javascript:;" onClick="start_over();">Start Over</a>
</div>
</div>
</div>
</div>
<footer></footer>
</body>
</html>
// Code goes here
$(function() {
$('input[type="radio"][name="binary_input"]').click(function () { $closestForm = $(this).parents('form'); $closestForm.submit();});
$('#binary_input_btn').hide();
});
/* Styles go here */
html, body{
margin: 0;
padding: 0;
border: 0;
}
body {
font-family:Arial, sans-serif;
line-height:1.5;
font-size:16px;
background: #fff;
padding:5px;
word-wrap: break-word;
-webkit-text-size-adjust: none;
}
h1, h2, h3, h4, h5, h6{ font-weight: normal; }
p img { float: left; margin: 0 10px 5px 0; padding: 0; }
img { border: 0; max-width: 100%; }
/* Main Styles */
body{
margin: 0 auto 0 auto;
width:95%;
background: rgb(240,240,240);
}
header{
top:0; left:0;
height:45px;
float: top;
}
footer {
bottom:0; left:auto;
height:48px;
background-color:#c27b00;
border-top:1px solid #eee;
position:fixed;
width:95%;
margin: 0 auto;
z-index:2;
}
header, footer{
background-color: #DEEFFF;
padding:0;
//position:absolute;
//position:relative;
z-index:2;
font-size:20px;
//width:80%;
text-align:center;
color:#333;
font-weight:bold;
text-shadow:0 -1px 0 rgba(0,0,0,0.5);
line-height:45px;
}
h1{
margin:0;
text-transform: uppercase;
}
#wrap {
margin: 0 auto 0 auto;
top:45px; bottom:48px; left:0;
width:100%;
overflow:auto;
align:center;
}
#main-content {
width: 500px;
border: solid 1px #CCC;
padding: 15px;
margin: 10px auto;
background-color: #FFF;
}
.app_button, button {
-webkit-border-radius: 20px;
border-radius: 20px;
display: inline-block;
padding: 0 20px;
margin-bottom: 20px;
cursor: pointer;
width: 200px;
background:#F7941E;
background: -webkit-gradient(linear, 0 0, 0 70%, from(#F7941E), to(#D37F18));
background: linear-gradient(#F7941E, #D37F18 70%);
border: 1px solid #C97917;
font-size: 18px;
font-weight: 200;
text-shadow: 0 -1px 0 #7E4B0D;
height: 40px;
line-height: 40px;
color:#fff;
text-align: center;
}
#output_div {
margin:0 auto 0 auto;
width:200px;
display: none;
color: rgb(0, 0, 0);
text-align: center;
}
#input_div {
margin:0 auto 0 auto;
width:200px;
display: none;
color: rgb(0, 0, 0);
}
#radio_input_div {
margin:0 auto 0 auto;
width:200px;
display: none;
color: rgb(0, 0, 0);
}
#finish_control_div {
margin:0 auto 0 auto;
width:200px;
display: none;
}
#control_div {
margin:0 auto 0 auto;
width:200px;
display: inline;
}
#finished_control_div {
margin: 5px auto 0 auto;
font-size: 12px;
display: none;
width:200px;
}
/* parser generated by jison 0.4.4 */
/*
Returns a Parser object of the following structure:
Parser: {
yy: {}
}
Parser.prototype: {
yy: {},
trace: function(),
symbols_: {associative list: name ==> number},
terminals_: {associative list: number ==> name},
productions_: [...],
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
table: [...],
defaultActions: {...},
parseError: function(str, hash),
parse: function(input),
lexer: {
EOF: 1,
parseError: function(str, hash),
setInput: function(input),
input: function(),
unput: function(str),
more: function(),
less: function(n),
pastInput: function(),
upcomingInput: function(),
showPosition: function(),
test_match: function(regex_match_array, rule_index),
next: function(),
lex: function(),
begin: function(condition),
popState: function(),
_currentRules: function(),
topState: function(),
pushState: function(condition),
options: {
ranges: boolean (optional: true ==> token location info will include a .range[] member)
flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
},
performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
rules: [...],
conditions: {associative list: name ==> set},
}
}
token location info (@$, _$, etc.): {
first_line: n,
last_line: n,
first_column: n,
last_column: n,
range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)
}
the parseError function receives a 'hash' object with these members for lexer and parser errors: {
text: (matched text)
token: (the produced terminal token, if any)
line: (yylineno)
}
while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
loc: (yylloc)
expected: (string describing the set of expected tokens)
recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
}
*/
var prolog = (function(){
var parser = {trace: function trace() { },
yy: {},
symbols_: {"error":2,"expressions":3,"program":4,"EOF":5,"clauselist":6,"query":7,"clause":8,"predicate":9,"PERIOD":10,"NECK":11,"predicatelist":12,"COMMA":13,"atom":14,"LEFTPAREN":15,"termlist":16,"RIGHTPAREN":17,"VARIABLE":18,"EQCMP":19,"string":20,"ASSIGN":21,"CUT":22,"term":23,"QUERYSYMBOL":24,"SMALLATOM":25,"STRING":26,"$accept":0,"$end":1},
terminals_: {2:"error",5:"EOF",10:"PERIOD",11:"NECK",13:"COMMA",15:"LEFTPAREN",17:"RIGHTPAREN",18:"VARIABLE",19:"EQCMP",21:"ASSIGN",22:"CUT",24:"QUERYSYMBOL",25:"SMALLATOM",26:"STRING"},
productions_: [0,[3,2],[4,1],[4,2],[4,1],[6,1],[6,2],[8,2],[8,4],[12,1],[12,3],[9,1],[9,4],[9,3],[9,3],[9,1],[16,1],[16,3],[23,1],[23,1],[7,3],[14,1],[14,1],[20,1]],
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
/* this == yyval */
var $0 = $$.length - 1;
switch (yystate) {
case 1:
//typeof console !== 'undefined' ? console.log($$[$0-1]) : print($$[$0-1]);
if(is_debug) {
console.log("here 0");
}
return $$[$0-1];
break;
case 2:
if(is_debug) {
console.log("here 1");
}
break;
case 3:
if(is_debug) {
console.log("here 1.1");
}
break;
case 4:
if(is_debug) {
console.log("here 2");
}
break;
case 5:
if(is_debug) {
console.log("here 3");
}
break;
case 6:
if(is_debug) {
console.log("here 4");
}
break;
case 7:
if(is_debug) {
console.log("here 5");
}
break;
case 8:
if(is_debug) {
console.log("here 6 1: " + $$[$0-3]);
console.log("_dbg rules.length: " + rules.length);
}
if(rules.length > 0) {
header = rules.pop();
if(is_debug) {
console.log("_dbg header rule name: " + header.name + " with arg: " + header.args[0]);
}
for(var i=0;i< header.args.length;i++) {
if(is_debug) {
console.log("_dbg header rule name: " + header.name + " adding term: " + header.args[i]);
}
//header.args[i] = new Term(header.args[i]);
}
while(rules.length > 0) {
var body_rule = rules.pop();
if(is_debug) {
console.log("_dbg adding to header body rule name: " + body_rule.name);
for(var i=0;i< body_rule.args.length;i++) {
console.log(" _dbg with arg: " + i + " "+ body_rule.args[i]);
}
}
if(body_rule.name == 'write' && body_rule.args[0]) {
if(is_debug) {
console.log("_dbg write body_rule.args[0]: " + body_rule.args[0]);
}
body_rule = new Rule('write(' + body_rule.args[0] + ')');
}
if(body_rule.name == 'i' && body_rule.args[0]) {
if(is_debug) {
console.log("_dbg i body_rule.args[0]: " + body_rule.args[0].name);
}
body_rule = new Rule('i(' + body_rule.args[0].name + ')');
}
//ex: iradiobtn(CPUCHOICE, {"Single":"single", "Dual":"dual"})
if(body_rule.name == 'iradiobtn' && body_rule.args[0] && body_rule.args[1]) {
if(is_debug) {
console.log("_dbg iradiobtn body_rule.args[0].name: " + body_rule.args[0].name + ' body_rule.args[1].name: ' + body_rule.args[1]);
}
body_rule = new Rule('iradiobtn(' + body_rule.args[0].name + ',' + body_rule.args[1] + ')');
console.log("_dbg body_rule.name: " + body_rule.name);
}
header.addRule(body_rule);
}
}
re.addRule(header);
break;
case 9:
if(is_debug) {
console.log("here 7 1: " + $$[$0]);
}
this.$=$$[$0];
break;
case 10:
if(is_debug) {
console.log("here 8");
}
break;
case 11:
if(is_debug) {
console.log("here 9 1: " + $$[$0]);
}
this.$=$$[$0];
var r = new Rule($$[$0]);
rules.unshift(r);
break;
case 12:
if(is_debug) {
console.log("here 10");
console.log("here 10 adding rule: " + $$[$0-3] + " with arg: " + args[0].name);
}
var r = new Rule($$[$0-3]);
for(var i=0;i<args.length;i++) {
r.addArg(args[i]);
}
rules.unshift(r);
args = [];
break;
case 13:
this.$=$$[$0-2]+$$[$0-1]+$$[$0]
var r = new Rule(this.$);
rules.unshift(r);
if(is_debug) {
console.log("here 10.1: " + this.$);
}
break;
case 14:
this.$=$$[$0-2]+$$[$0-1]+$$[$0]
var r = new Rule(this.$);
rules.unshift(r);
if(is_debug) {
console.log("here 10.2: " + this.$);
}
break;
case 15:
this.$=$$[$0];
var r = new Rule(this.$);
rules.unshift(r);
if(is_debug) {
console.log("here 10.3: " + this.$);
}
break;
case 16:
if(is_debug) {
console.log("here 11 1: " + $$[$0]);
}
this.$ = $$[$0]
break;
case 17:
if(is_debug) {
console.log("here 12");
}
break;
case 18:
if(is_debug) {
console.log("here 14 1: " + $$[$0]);
}
this.$ = $$[$0];
args.push($$[$0]);
break;
case 19:
if(is_debug) {
console.log("here 15 1: " + $$[$0]);
}
this.$ = $$[$0];
var t_var = new Term(this.$);
args.push(t_var);
break;
case 20:
if(is_debug) {
console.log("here 16 1: " + $$[$0-2]);
console.log("here 16 2: " + $$[$0-1]);
}
break;
case 21:
if(is_debug) {
console.log("here 18 1: " + $$[$0]);
}
this.$=$$[$0];
break;
case 22:
if(is_debug) {
console.log("here 19 1: " + $$[$0]);
}
this.$=$$[$0];
break;
case 23:
this.$ = $$[$0].substring(1, $$[$0].length - 1);//js
break;
}
},
table: [{3:1,4:2,6:3,7:4,8:5,9:7,14:8,18:[1,9],20:12,22:[1,10],24:[1,6],25:[1,11],26:[1,13]},{1:[3]},{5:[1,14]},{5:[2,2],7:15,8:16,9:7,14:8,18:[1,9],20:12,22:[1,10],24:[1,6],25:[1,11],26:[1,13]},{5:[2,4]},{5:[2,5],18:[2,5],22:[2,5],24:[2,5],25:[2,5],26:[2,5]},{9:18,12:17,14:8,18:[1,9],20:12,22:[1,10],25:[1,11],26:[1,13]},{10:[1,19],11:[1,20]},{10:[2,11],11:[2,11],13:[2,11],15:[1,21]},{19:[1,22],21:[1,23]},{10:[2,15],11:[2,15],13:[2,15]},{10:[2,21],11:[2,21],13:[2,21],15:[2,21],17:[2,21]},{10:[2,22],11:[2,22],13:[2,22],15:[2,22],17:[2,22]},{10:[2,23],11:[2,23],13:[2,23],15:[2,23],17:[2,23]},{1:[2,1]},{5:[2,3]},{5:[2,6],18:[2,6],22:[2,6],24:[2,6],25:[2,6],26:[2,6]},{10:[1,24],13:[1,25]},{10:[2,9],13:[2,9]},{5:[2,7],18:[2,7],22:[2,7],24:[2,7],25:[2,7],26:[2,7]},{9:18,12:26,14:8,18:[1,9],20:12,22:[1,10],25:[1,11],26:[1,13]},{14:29,16:27,18:[1,30],20:12,23:28,25:[1,11],26:[1,13]},{20:31,26:[1,13]},{20:32,26:[1,13]},{5:[2,20]},{9:33,14:8,18:[1,9],20:12,22:[1,10],25:[1,11],26:[1,13]},{10:[1,34],13:[1,25]},{13:[1,36],17:[1,35]},{13:[2,16],17:[2,16]},{13:[2,18],17:[2,18]},{13:[2,19],17:[2,19]},{10:[2,13],11:[2,13],13:[2,13]},{10:[2,14],11:[2,14],13:[2,14]},{10:[2,10],13:[2,10]},{5:[2,8],18:[2,8],22:[2,8],24:[2,8],25:[2,8],26:[2,8]},{10:[2,12],11:[2,12],13:[2,12]},{14:29,18:[1,30],20:12,23:37,25:[1,11],26:[1,13]},{13:[2,17],17:[2,17]}],
defaultActions: {4:[2,4],14:[2,1],15:[2,3],24:[2,20]},
parseError: function parseError(str, hash) {
if (hash.recoverable) {
this.trace(str);
} else {
throw new Error(str);
}
},
parse: function parse(input) {
var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
this.lexer.setInput(input);
this.lexer.yy = this.yy;
this.yy.lexer = this.lexer;
this.yy.parser = this;
if (typeof this.lexer.yylloc == 'undefined') {
this.lexer.yylloc = {};
}
var yyloc = this.lexer.yylloc;
lstack.push(yyloc);
var ranges = this.lexer.options && this.lexer.options.ranges;
if (typeof this.yy.parseError === 'function') {
this.parseError = this.yy.parseError;
} else {
this.parseError = Object.getPrototypeOf(this).parseError;
}
function popStack(n) {
stack.length = stack.length - 2 * n;
vstack.length = vstack.length - n;
lstack.length = lstack.length - n;
}
function lex() {
var token;
token = self.lexer.lex() || EOF;
if (typeof token !== 'number') {
token = self.symbols_[token] || token;
}
return token;
}
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
while (true) {
state = stack[stack.length - 1];
if (this.defaultActions[state]) {
action = this.defaultActions[state];
} else {
if (symbol === null || typeof symbol == 'undefined') {
symbol = lex();
}
action = table[state] && table[state][symbol];
}
if (typeof action === 'undefined' || !action.length || !action[0]) {
var errStr = '';
expected = [];
for (p in table[state]) {
if (this.terminals_[p] && p > TERROR) {
expected.push('\'' + this.terminals_[p] + '\'');
}
}
if (this.lexer.showPosition) {
errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + this.lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
} else {
errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
}
this.parseError(errStr, {
text: this.lexer.match,
token: this.terminals_[symbol] || symbol,
line: this.lexer.yylineno,
loc: yyloc,
expected: expected
});
}
if (action[0] instanceof Array && action.length > 1) {
throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
}
switch (action[0]) {
case 1:
stack.push(symbol);
vstack.push(this.lexer.yytext);
lstack.push(this.lexer.yylloc);
stack.push(action[1]);
symbol = null;
if (!preErrorSymbol) {
yyleng = this.lexer.yyleng;
yytext = this.lexer.yytext;
yylineno = this.lexer.yylineno;
yyloc = this.lexer.yylloc;
if (recovering > 0) {
recovering--;
}
} else {
symbol = preErrorSymbol;
preErrorSymbol = null;
}
break;
case 2:
len = this.productions_[action[1]][1];
yyval.$ = vstack[vstack.length - len];
yyval._$ = {
first_line: lstack[lstack.length - (len || 1)].first_line,
last_line: lstack[lstack.length - 1].last_line,
first_column: lstack[lstack.length - (len || 1)].first_column,
last_column: lstack[lstack.length - 1].last_column
};
if (ranges) {
yyval._$.range = [
lstack[lstack.length - (len || 1)].range[0],
lstack[lstack.length - 1].range[1]
];
}
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
if (typeof r !== 'undefined') {
return r;
}
if (len) {
stack = stack.slice(0, -1 * len * 2);
vstack = vstack.slice(0, -1 * len);
lstack = lstack.slice(0, -1 * len);
}
stack.push(this.productions_[action[1]][0]);
vstack.push(yyval.$);
lstack.push(yyval._$);
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
stack.push(newState);
break;
case 3:
return true;
}
}
return true;
}};
var rules = [];
var args = [];
var re = RuleEngine.getREInst();
/* generated by jison-lex 0.2.0 */
var lexer = (function(){
var lexer = {
EOF:1,
parseError:function parseError(str, hash) {
if (this.yy.parser) {
this.yy.parser.parseError(str, hash);
} else {
throw new Error(str);
}
},
// resets the lexer, sets new input
setInput:function (input) {
this._input = input;
this._more = this._backtrack = this.done = false;
this.yylineno = this.yyleng = 0;
this.yytext = this.matched = this.match = '';
this.conditionStack = ['INITIAL'];
this.yylloc = {
first_line: 1,
first_column: 0,
last_line: 1,
last_column: 0
};
if (this.options.ranges) {
this.yylloc.range = [0,0];
}
this.offset = 0;
return this;
},
// consumes and returns one char from the input
input:function () {
var ch = this._input[0];
this.yytext += ch;
this.yyleng++;
this.offset++;
this.match += ch;
this.matched += ch;
var lines = ch.match(/(?:\r\n?|\n).*/g);
if (lines) {
this.yylineno++;
this.yylloc.last_line++;
} else {
this.yylloc.last_column++;
}
if (this.options.ranges) {
this.yylloc.range[1]++;
}
this._input = this._input.slice(1);
return ch;
},
// unshifts one char (or a string) into the input
unput:function (ch) {
var len = ch.length;
var lines = ch.split(/(?:\r\n?|\n)/g);
this._input = ch + this._input;
this.yytext = this.yytext.substr(0, this.yytext.length - len - 1);
//this.yyleng -= len;
this.offset -= len;
var oldLines = this.match.split(/(?:\r\n?|\n)/g);
this.match = this.match.substr(0, this.match.length - 1);
this.matched = this.matched.substr(0, this.matched.length - 1);
if (lines.length - 1) {
this.yylineno -= lines.length - 1;
}
var r = this.yylloc.range;
this.yylloc = {
first_line: this.yylloc.first_line,
last_line: this.yylineno + 1,
first_column: this.yylloc.first_column,
last_column: lines ?
(lines.length === oldLines.length ? this.yylloc.first_column : 0)
+ oldLines[oldLines.length - lines.length].length - lines[0].length :
this.yylloc.first_column - len
};
if (this.options.ranges) {
this.yylloc.range = [r[0], r[0] + this.yyleng - len];
}
this.yyleng = this.yytext.length;
return this;
},
// When called from action, caches matched text and appends it on next action
more:function () {
this._more = true;
return this;
},
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
reject:function () {
if (this.options.backtrack_lexer) {
this._backtrack = true;
} else {
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
text: "",
token: null,
line: this.yylineno
});
}
return this;
},
// retain first n characters of the match
less:function (n) {
this.unput(this.match.slice(n));
},
// displays already matched input, i.e. for error messages
pastInput:function () {
var past = this.matched.substr(0, this.matched.length - this.match.length);
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
},
// displays upcoming input, i.e. for error messages
upcomingInput:function () {
var next = this.match;
if (next.length < 20) {
next += this._input.substr(0, 20-next.length);
}
return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
},
// displays the character position where the lexing error occurred, i.e. for error messages
showPosition:function () {
var pre = this.pastInput();
var c = new Array(pre.length + 1).join("-");
return pre + this.upcomingInput() + "\n" + c + "^";
},
// test the lexed token: return FALSE when not a match, otherwise return token
test_match:function (match, indexed_rule) {
var token,
lines,
backup;
if (this.options.backtrack_lexer) {
// save context
backup = {
yylineno: this.yylineno,
yylloc: {
first_line: this.yylloc.first_line,
last_line: this.last_line,
first_column: this.yylloc.first_column,
last_column: this.yylloc.last_column
},
yytext: this.yytext,
match: this.match,
matches: this.matches,
matched: this.matched,
yyleng: this.yyleng,
offset: this.offset,
_more: this._more,
_input: this._input,
yy: this.yy,
conditionStack: this.conditionStack.slice(0),
done: this.done
};
if (this.options.ranges) {
backup.yylloc.range = this.yylloc.range.slice(0);
}
}
lines = match[0].match(/(?:\r\n?|\n).*/g);
if (lines) {
this.yylineno += lines.length;
}
this.yylloc = {
first_line: this.yylloc.last_line,
last_line: this.yylineno + 1,
first_column: this.yylloc.last_column,
last_column: lines ?
lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
this.yylloc.last_column + match[0].length
};
this.yytext += match[0];
this.match += match[0];
this.matches = match;
this.yyleng = this.yytext.length;
if (this.options.ranges) {
this.yylloc.range = [this.offset, this.offset += this.yyleng];
}
this._more = false;
this._backtrack = false;
this._input = this._input.slice(match[0].length);
this.matched += match[0];
token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
if (this.done && this._input) {
this.done = false;
}
if (token) {
if (this.options.backtrack_lexer) {
delete backup;
}
return token;
} else if (this._backtrack) {
// recover context
for (var k in backup) {
this[k] = backup[k];
}
return false; // rule action called reject() implying the next rule should be tested instead.
}
if (this.options.backtrack_lexer) {
delete backup;
}
return false;
},
// return next match in input
next:function () {
if (this.done) {
return this.EOF;
}
if (!this._input) {
this.done = true;
}
var token,
match,
tempMatch,
index;
if (!this._more) {
this.yytext = '';
this.match = '';
}
var rules = this._currentRules();
for (var i = 0; i < rules.length; i++) {
tempMatch = this._input.match(this.rules[rules[i]]);
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
match = tempMatch;
index = i;
if (this.options.backtrack_lexer) {
token = this.test_match(tempMatch, rules[i]);
if (token !== false) {
return token;
} else if (this._backtrack) {
match = false;
continue; // rule action called reject() implying a rule MISmatch.
} else {
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
return false;
}
} else if (!this.options.flex) {
break;
}
}
}
if (match) {
token = this.test_match(match, rules[index]);
if (token !== false) {
return token;
}
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
return false;
}
if (this._input === "") {
return this.EOF;
} else {
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
text: "",
token: null,
line: this.yylineno
});
}
},
// return next match that has a token
lex:function lex() {
var r = this.next();
if (r) {
return r;
} else {
return this.lex();
}
},
// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
begin:function begin(condition) {
this.conditionStack.push(condition);
},
// pop the previously active lexer condition state off the condition stack
popState:function popState() {
var n = this.conditionStack.length - 1;
if (n > 0) {
return this.conditionStack.pop();
} else {
return this.conditionStack[0];
}
},
// produce the lexer rule set which is active for the currently active lexer condition state
_currentRules:function _currentRules() {
if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
} else {
return this.conditions["INITIAL"].rules;
}
},
// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
topState:function topState(n) {
n = this.conditionStack.length - 1 - Math.abs(n || 0);
if (n >= 0) {
return this.conditionStack[n];
} else {
return "INITIAL";
}
},
// alias for begin(condition)
pushState:function pushState(condition) {
this.begin(condition);
},
// return the number of states currently on the stack
stateStackSize:function stateStackSize() {
return this.conditionStack.length;
},
options: {},
performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
var YYSTATE=YY_START;
switch($avoiding_name_collisions) {
case 0:/* skip whitespace */
break;
case 1:return 26;
break;
case 2:return 26;
break;
case 3:return 'DIGIT';
break;
case 4:return 18;
break;
case 5:return 25;
break;
case 6:return 'LOWCASELETTER';
break;
case 7:return 'UPPERCASELETTER';
break;
case 8:return 19;
break;
case 9:return 21;
break;
case 10:return 13;
break;
case 11:return 10;
break;
case 12:return 11;
break;
case 13:return 22;
break;
case 14:return 24;
break;
case 15:return 15;
break;
case 16:return 17;
break;
case 17:return 5;
break;
case 18:return 'INVALID';
break;
}
},
rules: [/^(?:\s+)/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:[0-9])/,/^(?:[A-Z_]\w*)/,/^(?:[a-z_]\w*)/,/^(?:[a-z])/,/^(?:[A-Z])/,/^(?:==)/,/^(?:=)/,/^(?:,)/,/^(?:\.)/,/^(?::-)/,/^(?:!)/,/^(?:\?-)/,/^(?:\()/,/^(?:\))/,/^(?:$)/,/^(?:.)/],
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18],"inclusive":true}}
};
return lexer;
})();
parser.lexer = lexer;
function Parser () {
this.yy = {};
}
Parser.prototype = parser;parser.Parser = Parser;
return new Parser;
})();
function setup_re() {
var re = RuleEngine.getREInst();
var source = "\
get_diybio_help(DIYBIO_HELP):- write('Do you need help with changing a tire?'), i(IS_NEED_HELP), \
handle_need_help(DIYBIO_HELP, IS_NEED_HELP).\
handle_need_help(DIYBIO_HELP, IS_NEED_HELP):- IS_NEED_HELP == 'yes', write('What solution approach best describes how you want to fix your tire?'), \
iradiobtn(BIO_AREA, '\{\"Do it myself\":\"myself\", \"Get someone else to do it?\":\"tireservice\"\}'), \
handle_bio_area_choice(DIYBIO_HELP, BIO_AREA).\
handle_bio_area_choice(DIYBIO_HELP, BIO_AREA):- BIO_AREA == 'myself', DIYBIO_HELP='Watch youtube video: www.youtube.com/watch?v=joBmbh0AGSQ', !. \
handle_bio_area_choice(DIYBIO_HELP, BIO_AREA):- BIO_AREA == 'tireservice', DIYBIO_HELP='call AAA towing/road service at 1 800 222-4357', !. ";
prolog.parse(source);
return re;
}
var Util = (function () {
function Util() { }
Util.is_in_browser = function is_in_browser() {
return !(typeof window === 'undefined');
}
Util.output = function output(s) {
if(Util.is_in_browser()) {
document.getElementById('output_div').innerHTML = s;
} else {
console.log(s + '\n');
}
}
Util.inputRadio = function inputRadio(cb, radio_data) {
RuleEngine.async_hold = true;
if(is_debug) {
console.log("_dbg in input");
console.log("_dbg rule_firing # b_args: " + RuleEngine.rule_firing.b_args.length);
}
if(Util.is_in_browser()) {
var radio_input_div = document.getElementById("radio_input_div");
var btn_string = '';
var pre_radio_html = '<input type="radio" name="radio_input" value="';
for(var k in radio_data) {
if(radio_data.hasOwnProperty(k)) {
console.log('key is: ' + k + ', value is: ' + radio_data[k]);
btn_string += pre_radio_html + radio_data[k] + '">' + k + '<br>';
}
}
console.log("_dbg btn_string: " + btn_string);
$('#radio_input_div').html('\
<form id="radio_input_form" method="POST" onsubmit="Util.handle_radio_input(); return false;">\
' + btn_string + ' \
<input type="submit" value="Continue" onclick="Util.handle_radio_input();">\
</form>');
$('input[type="radio"][name="radio_input"]').click(function () { $closestForm = $(this).parents('form'); $closestForm.submit();});
$('#radio_input_btn').hide();
radio_input_div.style.display = "inline";
RuleEngine.input_cb = cb;
} else {
var prompt = require('prompt');
prompt.start();
prompt.get([
'input_str'
], function (err, result) {
if(err) {
return onErr(err);
}
if(is_debug) {
console.log('Command-line input received:');
console.log(' input_str: ' + result.input_str);
}
cb(result.input_str);
});
function onErr(err) {
console.log(err);
return 1;
}
}
}
Util.input = function input(cb) {
RuleEngine.async_hold = true;
if(is_debug) {
console.log("_dbg in input");
console.log("_dbg rule_firing # b_args: " + RuleEngine.rule_firing.b_args.length);
}
if(Util.is_in_browser()) {
var input_div = document.getElementById("input_div");
input_div.style.display = "inline";
RuleEngine.input_cb = cb;
} else {
var prompt = require('prompt');
prompt.start();
prompt.get([
'input_str'
], function (err, result) {
if(err) {
return onErr(err);
}
if(is_debug) {
console.log('Command-line input received:');
console.log(' input_str: ' + result.input_str);
}
cb(result.input_str);
});
function onErr(err) {
console.log(err);
return 1;
}
}
}
Util.add_qa_bool_rule = function add_qa_bool_rule() {
var re = RuleEngine.getREInst();
var qa_bool_rule = new Rule('qa_bool');
var qa_question_term = new Term('Q');
var qa_answer_term = new Term('BOOL_A');
qa_bool_rule.addArg(qa_question_term);
qa_bool_rule.addArg(qa_answer_term);
re.addRule(qa_bool_rule);
var qa_rule_o1 = new Rule('ov(Q)');
re.addRule(qa_rule_o1);
qa_bool_rule.addRule(qa_rule_o1);
var qa_rule_i1 = new Rule('i(BOOL_A)');
re.addRule(qa_rule_i1);
qa_bool_rule.addRule(qa_rule_i1);
}
Util.handle_radio_input = function handle_radio_input(document) {
console.log("_dbg in handle_radio_input");
var radio_val = $("#radio_input_form input[type='radio']:checked").val();
console.log("_dbg radio_val: " + radio_val);
$('#radio_input_div').hide();
$("input:radio[name='radio_input']").each(function () { $(this).prop('checked', false); });
RuleEngine.input_cb(radio_val);
}
Util.handle_binary_input = function handle_binary_input(document) {
console.log("_dbg in handle_binary_input");
var radio_val = $("#input_form input[type='radio']:checked").val();
console.log("_dbg radio_val: " + radio_val);
$('#input_div').hide();
$("input:radio[name='binary_input']").each(function () { $(this).prop('checked', false); });
RuleEngine.input_cb(radio_val);
}
Util.create_rule_from_qa_table = function create_rule_from_qa_table(input_rule_name, input_rulehdr_args, qa_t, call_rule_name) {
var qa_input_rule = Util.create_rule_header(input_rule_name, input_rulehdr_args);
var call_rule_args = [];
for(var i = 0; i < qa_t.length; i++) {
var qa_info = qa_t[i];
qa_input_rule.rules.push(new Rule('o(' + qa_info[0] + ')'));
if(qa_info[1] == 'yes_no') {
qa_input_rule.rules.push(new Rule('i(' + qa_info[2] + ')'));
call_rule_args.push(new Term(qa_info[2]));
}
}
for(var i = 0; i < input_rulehdr_args.length; i++) {
call_rule_args.push(new Term(input_rulehdr_args[i].name));
}
var call_rule = Util.create_rule_header(call_rule_name, call_rule_args);
qa_input_rule.rules.push(call_rule);
return qa_input_rule;
}
Util.gen_rules_from_truth_table = function gen_rules_from_truth_table(rule_name, header_args, tt) {
var generated_rules = [];
for(var i = 0; i < tt.length; i++) {
var rule = Util.create_rule_header(rule_name, header_args);
var body_tt_row = tt[i];
for(var j = 0; j < body_tt_row.length; j++) {
if(body_tt_row[j] === undefined) {
continue;
}
if(j == body_tt_row.length - 2) {
if(body_tt_row[j] !== undefined) {
rule.addRule(new Rule(header_args[j].name + '=' + body_tt_row[j]));
}
} else {
if(j == body_tt_row.length - 1) {
if(Object.prototype.toString.call(body_tt_row[j]) == "[object Array]") {
var suffix_rules = body_tt_row[j];
for(var k = 0; k < suffix_rules.length; k++) {
rule.addRule(suffix_rules[k]);
}
}
} else {
rule.addRule(new Rule(header_args[j].name + '==' + body_tt_row[j]));
}
}
}
generated_rules.push(rule);
}
return generated_rules;
}
Util.create_rule_header = function create_rule_header(rule_name, header_args) {
var new_rule = new Rule(rule_name);
for(var i = 0; i < header_args.length; i++) {
new_rule.addArg(header_args[i]);
}
return new_rule;
}
return Util;
})();
var is_debug = true;
var Types = (function () {
function Types() { }
Types.types = [];
Types.registerType = function registerType(clsName, classDcl) {
Types.types[clsName] = classDcl;
}
return Types;
})();
var Atom = (function () {
function Atom(name) {
this.name = name;
}
Atom.prototype.deepcopy = function () {
var atom_copy = new Atom(this.name);
return atom_copy;
};
return Atom;
})();
Types.registerType('Atom', Atom);
var Term = (function () {
function Term(name) {
this.name = name;
this.grounded = this;
}
Term.prototype.deepcopy = function () {
var term_copy = new Term(this.name);
term_copy.name = this.name;
if(!this.isGrounded()) {
term_copy.grounded = this.grounded;
} else {
term_copy.grounded = term_copy;
}
return term_copy;
};
Term.prototype.isBoundorAliased = function () {
var ret_val = false;
if(RuleEngine.getTypeName(this.grounded) == 'Atom') {
ret_val = true;
}
if(RuleEngine.getTypeName(this.grounded) == 'Term') {
ret_val = true;
}
return ret_val;
};
Term.prototype.isFree = function () {
if(this.grounded == this) {
return true;
} else {
return false;
}
};
Term.prototype.isGrounded = function () {
var is_grounded = true;
if(this.grounded == this) {
is_grounded = false;
} else {
if(this.isBoundorAliased()) {
is_grounded = this.grounded.isGrounded();
}
}
return is_grounded;
};
Term.prototype.reset = function () {
this.grounded = this;
};
Term.prototype.unify = function (t) {
if(is_debug) {
console.log("_dbg in unify");
console.log("_dbg this.name: " + this.name);
console.log("_dbg t type: " + RuleEngine.getTypeName(t));
if(RuleEngine.getTypeName(t)) {
console.log("_dbg value: " + t);
}
}
var unified = false;
if(this.isFree()) {
if(is_debug) {
console.log("_dbg term is free, assigning grounded");
if(RuleEngine.getTypeName(t)) {
console.log("_dbg to Term with name: " + t.name);
}
}
this.grounded = t;
unified = true;
} else {
if(this.isBoundorAliased()) {
unified = this.grounded.unify(t);
} else {
unified = false;
}
}
if(unified) {
RuleEngine.choices.push(this);
}
return unified;
};
Term.prototype.getGrounded = function () {
if(is_debug) {
}
if(this.isFree()) {
return this;
}
var ret_val = this.grounded;
if(this.isBoundorAliased()) {
if(is_debug) {
}
ret_val = this.grounded.getGrounded();
if(is_debug) {
}
}
return ret_val;
};
return Term;
})();
Types.registerType('Term', Term);
var Rule = (function () {
function Rule(name) {
this.args = [];
this.b_args = [];
this.rules = [];
this.is_context_change = false;
this.non_call_regex = /=|fail|!|o\(|ov\(|i\(|write\(|iradiobtn\(/;
this.solutions = [];
this.name = name;
this.proven = false;
}
Rule.prototype.deepcopy = function () {
if(is_debug) {
console.log("_dbg in Rule.deepcopy");
}
var rule_copy = new Rule(this.name);
for(var i = 0; i < this.args.length; i++) {
if(is_debug) {
console.log("_dbg about to call deepcopy on arg with name: " + this.args[i].name);
}
rule_copy.args.push(this.args[i].deepcopy());
}
for(var r = 0; r < this.rules.length; r++) {
var call_copy = new Rule(this.rules[r].name);
for(var a = 0; a < this.rules[r].args.length; a++) {
call_copy.args.push(this.rules[r].args[a].deepcopy());
}
for(var b = 0; b < this.rules[r].b_args.length; b++) {
call_copy.b_args.push(this.rules[r].b_args[b].deepcopy());
}
rule_copy.rules.unshift(call_copy);
}
rule_copy.proven = this.proven;
rule_copy.solutions = this.solutions;
rule_copy.is_context_change = this.is_context_change;
if(is_debug) {
console.log("_dbg about to return from Rule.deepcopy");
}
return rule_copy;
};
Rule.prototype.addArg = function (arg) {
this.args.push(arg);
};
Rule.prototype.addBarg = function (b_arg) {
this.b_args.push(b_arg);
};
Rule.prototype.addRule = function (rule) {
this.rules.push(rule);
};
Rule.prototype.is_query = function () {
return !this.rules.length && !this.non_call_regex.test(this.name);
};
Rule.prototype.is_non_call = function () {
return !this.rules.length && !this.args.length && this.non_call_regex.test(this.name);
};
return Rule;
})();
Types.registerType('Rule', Rule);
var Choice = (function () {
function Choice(query, rule, body_rules) {
this.body_rules = [];
this.query = query;
this.rule = rule;
this.body_rules = body_rules;
}
return Choice;
})();
Types.registerType('Choice', Choice);
var RuleEngine = (function () {
function RuleEngine() { }
RuleEngine.re_inst = 0;
RuleEngine.rules = [];
RuleEngine.gnd_val_only = false;
RuleEngine.no_solutions_found_txt = '';
RuleEngine.choices = [];
RuleEngine.body_rules = [];
RuleEngine.rule_firing = undefined;
RuleEngine.body_rule_firing = undefined;
RuleEngine.async_hold = false;
RuleEngine.base_query = undefined;
RuleEngine.input_cb = undefined;
RuleEngine.finished_cb = undefined;
RuleEngine.more_solutions_prompt = true;
RuleEngine.reset = function reset() {
RuleEngine.re_inst = 0;
RuleEngine.rules = [];
RuleEngine.choices = [];
RuleEngine.body_rules = [];
RuleEngine.async_hold = false;
RuleEngine.input_cb = 0;
RuleEngine.base_query = 0;
RuleEngine.rule_firing = 0;
RuleEngine.body_rule_firing = 0;
RuleEngine.finished_cb = 0;
RuleEngine.more_solutions_prompt = true;
}
RuleEngine.prototype.isFinished = function () {
var is_finished = false;
if(RuleEngine.body_rules.length == 0) {
if(RuleEngine.choices.length == 0) {
is_finished = true;
}
}
return is_finished;
};
RuleEngine.prototype.handleBaseQueryFinish = function () {
if(RuleEngine.async_hold) {
return;
}
if(is_debug) {
console.log("_dbg in handleBaseQueryFinish");
}
if(RuleEngine.body_rules.length == 0) {
if(is_debug) {
console.log("_dbg base_query == r, about to call handleQueryResult");
}
if(this.isFinished()) {
if(RuleEngine.finished_cb) {
RuleEngine.finished_cb();
}
}
this.handleQueryResult();
}
};
RuleEngine.getREInst = function getREInst() {
if(!RuleEngine.re_inst) {
RuleEngine.re_inst = new RuleEngine();
}
return RuleEngine.re_inst;
}
RuleEngine.prototype.addBodyRule = function (rule) {
RuleEngine.body_rules.push(rule);
};
RuleEngine.prototype.addRule = function (rule) {
RuleEngine.rules.push(rule);
for(var i = 0; i < rule.rules.length; i++) {
if(!rule.is_query()) {
var foundRules = this.searchRules(RuleEngine.rules, rule.name, rule.args);
if(foundRules.length == 1) {
for(var j = 0; j < foundRules.length; j++) {
var found_bodyRule = foundRules[j];
if(found_bodyRule.is_non_call()) {
rule.rules[i] = found_bodyRule;
}
}
}
}
}
};
RuleEngine.getTypeName = function getTypeName(inst) {
var typeName = undefined;
for(var clsName in Types.types) {
if(inst instanceof Types.types[clsName]) {
typeName = clsName;
}
}
return typeName;
}
RuleEngine.findArg = function findArg(name, args) {
for(var i = 0; i < args.length; i++) {
if(name == args[i].name) {
return args[i];
}
}
}
RuleEngine.prototype.backTrack = function () {
var is_backTracked = false;
var found_choice = undefined;
RuleEngine.rule_firing = undefined;
RuleEngine.body_rule_firing = undefined;
RuleEngine.body_rules = [];
if(is_debug) {
console.log("_dbg in backTrack");
console.log("_dbg RuleEngine.choices.length: " + RuleEngine.choices.length);
RuleEngine.dump_choices();
}
while(!is_backTracked) {
if(RuleEngine.choices.length > 0) {
var choice_or_term = RuleEngine.choices.pop();
if(RuleEngine.getTypeName(choice_or_term) == 'Term') {
choice_or_term.reset();
} else {
if(RuleEngine.getTypeName(choice_or_term) == 'Choice') {
found_choice = choice_or_term;
is_backTracked = true;
} else {
throw new TypeError("BackTrack error, unknown type popped from choice point stack");
}
}
} else {
is_backTracked = true;
}
}
if(found_choice) {
RuleEngine.body_rules = found_choice.body_rules;
var rule_copy = this.prepareToFire(found_choice.query, found_choice.rule, false);
if(is_debug) {
if(!this.check_copy_args_link_to_base_args(rule_copy)) {
console.log("_dbg 6 rule_copy: " + rule_copy.name + " args not found in alias chain of base query args after unifying with query: " + found_choice.query.name);
} else {
console.log("_dbg 6 rule_copy: " + rule_copy.name + " args found in alias chain of base query args after unifying with query: " + found_choice.query.name);
}
}
this.fireRule(rule_copy);
} else {
if(is_debug) {
console.log("_dbg backTrack found no choices to fire on choice point stack");
}
}
};
RuleEngine.prototype.isArgsMatch = function (args1, args2) {
var match = true;
if(args1.length == args2.length) {
if(is_debug) {
console.log("_dbg num args match\n");
}
} else {
match = false;
}
return match;
};
RuleEngine.prototype.searchRules = function (rules, name, args) {
if(is_debug) {
console.log("_dbg in searchRules\n");
console.log("_dbg num rules searching: " + rules.length + "\n");
console.log("_dbg searching for name: " + name + "\n");
}
var foundRules = [];
for(var i in rules) {
if(is_debug) {
console.log("_dbg rule name: " + rules[i].name + "\n");
}
if(name == rules[i].name) {
if(is_debug) {
console.log("_dbg found rule\n");
}
if(this.isArgsMatch(rules[i].args, args)) {
if(is_debug) {
console.log("_dbg args match\n");
}
foundRules.push(rules[i]);
} else {
console.log("_dbg args do not match\n");
}
}
}
return foundRules;
};
RuleEngine.prototype.unifyHeaderBodyArgsToQueryArgs = function (query) {
if(is_debug) {
console.log("_dbg in unifyHeaderBodyArgsToQueryArgs");
}
var header = RuleEngine.rule_firing;
for(var i = 0; i < header.b_args.length; i++) {
for(var j = 0; j < query.args.length; j++) {
if(is_debug) {
console.log("_dbg cmp b arg name: " + query.args[j].name + " with header arg name" + header.b_args[i].name);
}
if(query.args[j].name == header.b_args[i].name) {
query.args[j] = header.b_args[i];
}
}
}
};
RuleEngine.prototype.unifyHeaderArgsToBodyCallArgs = function (rule) {
var header = rule;
var body_rules = rule.rules;
for(var k = 0; k < body_rules.length; k++) {
var body_rule = body_rules[k];
if(is_debug) {
console.log("_dbg in unifyHeaderArgsToBodyCallArgs h: " + header.name + " b: " + body_rule.name);
}
for(var i = 0; i < header.args.length; i++) {
for(var j = 0; j < body_rule.args.length; j++) {
if(is_debug) {
console.log("_dbg cmp b arg name: " + body_rule.args[j].name + " with header arg name" + header.args[i].name);
}
if(body_rule.args[j].name == header.args[i].name) {
body_rule.args[j] = header.args[i];
}
}
}
}
};
RuleEngine.prototype.unifyRuleHeaders = function (r1, r2) {
if(is_debug) {
console.log("_dbg in unifyRuleHeaders");
console.log("_dbg unifying r1: " + r1.name);
RuleEngine.dump_rule(r1);
console.log("_dbg with r2: " + r2.name);
RuleEngine.dump_rule(r2);
}
for(var i = 0; i < r1.args.length; i++) {
if(RuleEngine.getTypeName(r1.args[i]) == 'Term' && !r1.args[i].isGrounded()) {
if(is_debug) {
console.log("_dbg calling unify on arg: " + r1.args[i].name + " v: " + r1.args[i].getGrounded() + " with arg: " + r2.args[i].name + " v: " + r2.args[i].getGrounded());
}
r1.args[i].unify(r2.args[i]);
if(is_debug) {
console.log("_dbg unifying " + r2.args[i].name + " with " + r1.args[i].name);
console.log("_dbg r1.args[i].grounded type: " + RuleEngine.getTypeName(r1.args[i].grounded));
RuleEngine.dump_term_alias_chain(r1.args[i]);
if(r2.args[i].name == 'X1') {
var bq_hd_arg = RuleEngine.base_query.args[0];
console.log("\n_dbg dumping base query arg name: " + bq_hd_arg.name);
if(RuleEngine.is_term_in_alias_chain(r1.args[i], bq_hd_arg)) {
console.log("_dbg 2 term: " + r1.args[i].name + " is in alias chain of base query arg: " + bq_hd_arg.name);
} else {
console.log("_dbg 2 term: " + r1.args[i].name + " is not in alias chain of base query arg: " + bq_hd_arg.name);
}
if(RuleEngine.is_term_in_alias_chain(r2.args[i], bq_hd_arg)) {
console.log("_dbg term: " + r2.args[i].name + " is in alias chain of base query arg: " + bq_hd_arg.name);
} else {
console.log("_dbg term: " + r2.args[i].name + " is not in alias chain of base query arg: " + bq_hd_arg.name);
}
RuleEngine.dump_term_alias_chain(bq_hd_arg);
console.log("_dbg r1.args[i].getGrounded: " + r1.args[i].getGrounded());
}
}
} else {
if(RuleEngine.getTypeName(r2.args[i]) == 'Term' && !r2.args[i].isGrounded()) {
if(is_debug) {
console.log("_dbg calling unify on r2");
}
if(is_debug) {
console.log("_dbg unifying " + r1.args[i].name + " with " + r2.args[i].name);
}
r2.args[i].unify(r1.args[i]);
}
}
if((RuleEngine.getTypeName(r2.args[i]) == 'Term' && r2.args[i].isGrounded()) && (RuleEngine.getTypeName(r2.args[i]) == 'Term' && !r2.args[i].isGrounded())) {
throw "cannot unify two grounded header args";
}
}
if(is_debug) {
console.log("_dbg exiting unifyRuleHeaders");
}
};
RuleEngine.prototype.handleFoundRules = function (query, foundRules) {
if(is_debug) {
console.log("_dbg in handleFoundRules");
console.log("_dbg # foundRules: " + foundRules.length);
console.log("_dbg # RuleEngine.body_rules: " + RuleEngine.body_rules.length);
if(!this.check_copy_args_link_to_base_args(query)) {
console.log("_dbg 5 rule: " + query.name + " args not found in alias chain of base query args!");
} else {
console.log("_dbg 5 rule: " + query.name + " args found in alias chain of base query args!");
}
}
if(is_debug) {
console.log("_dbg choices before adding: ");
RuleEngine.dump_choices();
}
for(var i = foundRules.length - 1; i > 0; i--) {
var body_rules_copy = [];
for(var j = 0; j < RuleEngine.body_rules.length; j++) {
body_rules_copy.unshift(RuleEngine.body_rules[j].deepcopy());
}
var choice = new Choice(query, foundRules[i], body_rules_copy);
if(is_debug) {
console.log("_dbg adding choice: " + foundRules[i].name);
}
RuleEngine.choices.push(choice);
}
if(is_debug) {
console.log("_dbg choices after adding: ");
RuleEngine.dump_choices();
}
};
RuleEngine.prototype.check_copy_args_link_to_base_args = function (rule_copy) {
var bq_args = RuleEngine.base_query.args;
for(var i = 0; i < bq_args.length; i++) {
for(var j = 0; j < rule_copy.args.length; j++) {
if(RuleEngine.is_term_in_alias_chain(rule_copy.args[j], bq_args[i])) {
return true;
}
}
}
return false;
};
RuleEngine.prototype.prepareToFire = function (query, rule, is_body_rule) {
if(is_debug) {
console.log("_dbg in prepareToFire");
var rule_check = query;
if(!this.check_copy_args_link_to_base_args(rule_check)) {
console.log("_dbg 4 rule: " + rule_check.name + " args not found in alias chain of base query args!");
} else {
console.log("_dbg 4 rule: " + rule_check.name + " args found in alias chain of base query args!");
}
}
var rule_copy = rule.deepcopy();
if(rule_copy.rules.length > 0) {
this.unifyHeaderArgsToBodyCallArgs(rule_copy);
}
if(is_debug) {
if(query.name == 'choose_hd') {
console.log("_dbg choose_hd call: ");
RuleEngine.dump_rule(query);
}
}
if(!is_body_rule) {
this.unifyRuleHeaders(query, rule_copy);
} else {
RuleEngine.rule_firing.is_context_change = true;
if(is_debug) {
console.log("_dbg adding RuleEngine.rule_firing.is_context_change = true: " + RuleEngine.rule_firing.name);
}
this.addBodyRule(RuleEngine.rule_firing);
this.addHeaderBodyArgs(query);
this.unifyHeaderBodyArgsToQueryArgs(query);
this.unifyRuleHeaders(query, rule_copy);
}
if(is_debug) {
if(query.name == 'choose_hd') {
console.log("_dbg choose_hd call after unifyRuleHeaders: ");
RuleEngine.dump_rule(rule_copy);
}
}
if(is_debug) {
if(!this.check_copy_args_link_to_base_args(rule_copy)) {
console.log("_dbg 3 rule_copy: " + rule_copy.name + " args not found in alias chain of base query args after unifying with query: " + query.name);
} else {
console.log("_dbg 3 rule_copy: " + rule_copy.name + " args found in alias chain of base query args after unifying with query: " + query.name);
}
}
if(is_debug) {
if(query.name == 'choose_hd') {
console.log("_dbg choose_hd rule after unifying header and body args: ");
RuleEngine.dump_rule(rule_copy);
}
}
return rule_copy;
};
RuleEngine.prototype.popBodyRule = function () {
if(!RuleEngine.async_hold) {
if(is_debug) {
console.log("_dbg about to pop a body rule");
console.log("_dbg RuleEngine.body_rules.length: " + RuleEngine.body_rules.length);
}
var popped_body_rule = RuleEngine.body_rules.pop();
if(popped_body_rule && popped_body_rule.is_context_change) {
if(is_debug) {
console.log("_dbg context change to RuleEngine.rule_firing: " + popped_body_rule.name);
}
RuleEngine.rule_firing = popped_body_rule;
this.popBodyRule();
} else {
RuleEngine.body_rule_firing = popped_body_rule;
}
}
};
RuleEngine.prototype.handleAsyncInput = function (input_str) {
if(is_debug) {
console.log("_dbg in handleAsyncInput");
}
RuleEngine.async_hold = false;
var re = RuleEngine.getREInst();
var header = RuleEngine.rule_firing;
var bodyRule = RuleEngine.body_rule_firing;
if(bodyRule) {
if(is_debug) {
console.log("_dbg bodyRule is defined");
}
} else {
if(is_debug) {
console.log("_dbg bodyRule is not defined");
}
}
if(is_debug) {
console.log("_dbg bodyRule.name: " + bodyRule.name);
}
if(bodyRule.name.indexOf('i(') > -1) {
var r = /^i\((.*)\)/;
var arg_name = bodyRule.name.match(r)[1];
}
if(bodyRule.name.indexOf('iradiobtn(') > -1) {
var r = /^iradiobtn\((.*)\)/;
var radio_exp = bodyRule.name.match(r)[1];
var arg_name = radio_exp.substr(0, radio_exp.indexOf(','));
}
console.log("\n");
var arg = RuleEngine.findArg(arg_name, header.args);
if(!arg) {
arg = RuleEngine.findArg(arg_name, header.b_args);
}
if(!arg) {
if(is_debug) {
console.log("_dbg Term variable with name: " + arg_name + " not found, creating and adding to body args of header rule name:" + header.name);
}
arg = new Term(arg_name);
header.addBarg(arg);
}
if(is_debug) {
console.log("_dbg unifying value: " + input_str + " with arg name: " + arg.name);
}
arg.unify(input_str);
if(is_debug) {
console.log("_dbg num header.b_args: " + header.b_args.length);
}
re.handleNonCallAsync(false);
};
RuleEngine.prototype.addHeaderBodyArgs = function (call_rule) {
if(is_debug) {
console.log("_dbg in addHeaderBodyArgs");
}
var header = RuleEngine.rule_firing;
for(var i = 0; i < call_rule.args.length; i++) {
var arg = RuleEngine.findArg(call_rule.args[i].name, header.args);
if(!arg) {
if(is_debug) {
}
arg = RuleEngine.findArg(call_rule.args[i].name, header.b_args);
}
if(!arg) {
if(is_debug) {
console.log("_dbg adding term to header body args: " + call_rule.args[i].name);
}
arg = new Term(call_rule.args[i].name);
header.addBarg(arg);
}
}
};
RuleEngine.prototype.handleNonCallBodyRule = function (header, bodyRule) {
if(is_debug) {
console.log("_dbg in handleNonCallBodyRule\n");
console.log("_dbg header.name: " + header.name);
}
var is_fail = false;
if(bodyRule.name.indexOf('==') > -1) {
var n = bodyRule.name.split('==');
if(is_debug) {
console.log("_dbg n: " + JSON.stringify(n) + "\n");
console.log("_dbg num header args: " + header.args.length + "\n");
console.log("_dbg num header b_args: " + header.b_args.length + "\n");
}
var arg = RuleEngine.findArg(n[0], header.args);
if(!arg) {
if(is_debug) {
console.log("_dbg arg name: " + n[0] + " not found in header.args");
console.log("_dbg header.b_args: " + JSON.stringify(header.b_args) + "\n");
}
arg = RuleEngine.findArg(n[0], header.b_args);
}
if(is_debug) {
if(arg) {
console.log("_dbg arg name: " + arg.name + "\n");
console.log("_dbg == arg.getGrounded(): " + arg.getGrounded() + "\n");
} else {
console.log("_dbg arg name: " + n[0] + " not found in header.b_args:" + JSON.stringify(header.b_args) + "\n");
}
}
if(arg.getGrounded() != n[1]) {
is_fail = true;
}
} else {
if(bodyRule.name.indexOf('=') > -1) {
var n = bodyRule.name.split('=');
var arg = RuleEngine.findArg(n[0], header.args);
if(!arg) {
arg = RuleEngine.findArg(n[0], header.b_args);
}
if(!arg) {
if(is_debug) {
console.log("_dbg Term variable with name: " + n[0] + " not found, creating and adding to body args of header rule");
}
arg = new Term(n[0]);
header.addBarg(arg);
}
if(is_debug) {
console.log("_dbg about to unity value: " + n[1] + " with arg name: " + arg.name + "\n");
}
arg.unify(n[1]);
if(is_debug) {
RuleEngine.dump_term_alias_chain(arg);
var bq_hd_arg = RuleEngine.base_query.args[0];
RuleEngine.dump_term_alias_chain(bq_hd_arg);
}
} else {
if(bodyRule.name == '!') {
console.log("_dbg executing cut, emptying choice points");
RuleEngine.choices = [];
} else {
if(bodyRule.name.indexOf('fail') > -1) {
if(is_debug) {
console.log("_dbg executing fail");
}
is_fail = true;
} else {
if(bodyRule.name.indexOf('write(') > -1) {
var r = /^write\((.*)\)/;
Util.output(bodyRule.name.match(r)[1]);
} else {
if(bodyRule.name.indexOf('o(') > -1) {
var r = /^o\((.*)\)/;
Util.output(bodyRule.name.match(r)[1]);
} else {
if(bodyRule.name.indexOf('i(') > -1) {
var r = /^i\((.*)\)/;
var arg_name = bodyRule.name.match(r)[1];
if(is_debug) {
console.log("_dbg input into varible: " + arg_name);
}
Util.input(this.handleAsyncInput);
} else {
if(bodyRule.name.indexOf('iradiobtn(') > -1) {
var r = /^iradiobtn\((.*)\)/;
var radio_exp = bodyRule.name.match(r)[1];
var arg_name = radio_exp.substr(0, radio_exp.indexOf(','));
var radio_info = radio_exp.substr(radio_exp.indexOf(',') + 1, radio_exp.length);
if(is_debug) {
console.log("_dbg input radio button into variable: " + arg_name);
console.log("_dbg input radio button info: " + radio_info);
}
var radio_data = JSON.parse(radio_info);
Util.inputRadio(this.handleAsyncInput, radio_data);
} else {
if(bodyRule.name.indexOf('ov(') > -1) {
if(is_debug) {
console.log("_dbg in ov body rule");
}
var r = /^ov\((.*)\)/;
var arg_name = bodyRule.name.match(r)[1];
if(is_debug) {
console.log("_dbg arg_name: " + arg_name);
}
var arg = RuleEngine.findArg(arg_name, header.args);
if(!arg) {
arg = RuleEngine.findArg(arg_name, header.b_args);
}
Util.output(arg.getGrounded());
}
}
}
}
}
}
}
}
}
if(is_debug) {
console.log("_dbg about to call handleNonCallAsync");
console.log("_dbg is_fail: " + is_fail);
}
this.handleNonCallAsync(is_fail);
};
RuleEngine.prototype.prepareToCall = function (call_rule, is_body_rule) {
if (typeof is_body_rule === "undefined") { is_body_rule = false; }
if(is_debug) {
console.log("_dbg processing rule name: " + call_rule.name + " in prepareToCall");
RuleEngine.dump_rule(call_rule);
console.log("_dbg RuleEngine.rule_firing.name: " + RuleEngine.rule_firing.name);
}
this.addHeaderBodyArgs(call_rule);
var foundRules = this.searchRules(RuleEngine.rules, call_rule.name, call_rule.args);
if(is_debug) {
console.log("_dbg num rules found: " + foundRules.length + "\n");
}
this.handleFoundRules(call_rule, foundRules);
if(foundRules.length) {
if(is_debug) {
console.log("_dbg foundRules[0].rules.length: " + foundRules[0].rules.length);
}
var rule_copy = this.prepareToFire(call_rule, foundRules[0], is_body_rule);
if(is_debug) {
console.log("_dbg copy of rule name: " + call_rule.name);
RuleEngine.dump_rule(rule_copy);
}
return rule_copy;
}
};
RuleEngine.prototype.handleNonCallAsync = function (is_fail) {
if(is_debug) {
console.log("_dbg in handleNonCallAsync");
console.log("_dbg RuleEngine.async_hold: " + RuleEngine.async_hold);
if(RuleEngine.rule_firing.b_args.length > 0) {
console.log("RuleEngine.rule_firing.b_args[0].getGrounded(): " + RuleEngine.rule_firing.b_args[0].getGrounded());
}
}
if(RuleEngine.async_hold) {
return;
}
if(!RuleEngine.async_hold) {
if(is_debug) {
console.log("_dbg RuleEngine.async_hold is false");
}
if(is_fail) {
if(is_debug) {
console.log("_dbg fail detected in bodyRules execution, backtracking...");
}
this.backTrack();
}
this.popBodyRule();
if(is_debug) {
console.log("_dbg about to call handleBodyRule");
}
this.handleBodyRule();
this.handleBaseQueryFinish();
}
};
RuleEngine.prototype.handleBodyRule = function () {
if(is_debug) {
console.log("_dbg in handleBodyRule");
}
if(RuleEngine.async_hold) {
if(is_debug) {
console.log("_dbg async_hold is true not executing body rule");
}
return;
}
var header = RuleEngine.rule_firing;
var bodyRule = RuleEngine.body_rule_firing;
if(!bodyRule) {
return;
}
if(!bodyRule.is_non_call()) {
if(is_debug) {
console.log("_dbg bodyRule name: " + bodyRule.name + " is not non_call");
}
var is_body_rule = true;
var rule_copy = this.prepareToCall(bodyRule, is_body_rule);
this.fireRule(rule_copy);
} else {
if(is_debug) {
console.log("_dbg processing non call rule name: " + bodyRule.name);
}
this.handleNonCallBodyRule(header, bodyRule);
}
};
RuleEngine.prototype.fireRule = function (r) {
RuleEngine.rule_firing = r;
if(is_debug) {
console.log("_dbg firing rule: " + r.name + "\n");
console.log("_dbg r.rules.length: " + r.rules.length);
console.log("_dbg r.args[0]: " + RuleEngine.getTypeName(r.args[0]));
}
if(r.is_query()) {
if(is_debug) {
console.log("_dbg executing query rule: " + r.name + "\n");
}
var rule_copy = this.prepareToCall(r);
if(is_debug) {
console.log("_dbg about to fire rule_copy with name: " + rule_copy.name);
console.log("_dbg rule_copy.rules.length: " + rule_copy.rules.length);
}
this.fireRule(rule_copy);
if(RuleEngine.async_hold) {
return;
}
} else {
if(is_debug) {
console.log("_dbg rule: " + r.name + " is not a query\n");
}
}
for(var l in r.rules) {
var bodyRule = r.rules[l];
this.addBodyRule(bodyRule);
}
if(is_debug && r.rules.length) {
console.log("_dbg # body rules of rule " + r.name + ": " + r.rules.length);
console.log("_dbg added all body rules of rule: " + bodyRule.name);
RuleEngine.dump_body_rules();
}
this.popBodyRule();
if(is_debug) {
console.log("_dbg current rule firing: " + RuleEngine.rule_firing.name);
if(RuleEngine.body_rule_firing) {
console.log("_dbg body rule processing after popBodyRule: " + RuleEngine.body_rule_firing.name);
}
}
this.handleBodyRule();
if(is_debug) {
console.log("_dbg after handleBodyRule in fireRule");
}
};
RuleEngine.is_term_in_alias_chain = function is_term_in_alias_chain(needle, haystack) {
var done = false;
var found = false;
while(!done) {
if(needle == haystack) {
found = true;
done = true;
}
if(RuleEngine.getTypeName(haystack.grounded) != 'Term' || haystack.isFree()) {
done = true;
} else {
haystack = haystack.grounded;
}
}
return found;
}
RuleEngine.dump_term_alias_chain = function dump_term_alias_chain(t) {
return;
if(RuleEngine.getTypeName(t.grounded) != 'Term') {
console.log("_dbg t.name: " + t.name + " is bound to value" + t.grounded);
return;
}
console.log("_dbg dumping alias chain:");
console.log("_dbg t.name: " + t.name);
if(t.isFree()) {
console.log("_dbg t.name: " + t.name + " is free");
return;
}
if(t.isBoundorAliased()) {
if(RuleEngine.getTypeName(t.grounded) == 'Term') {
console.log("_dbg t.name: " + t.name + " is aliased to " + t.grounded.name);
RuleEngine.dump_term_alias_chain(t.grounded);
} else {
console.log("_dbg t.name: " + t.name + " is bound to value" + t.grounded);
}
}
}
RuleEngine.dump_rule = function dump_rule(r1) {
console.log("_dbg rule name: " + r1.name);
if(r1.args.length > 0) {
for(var i = 0; i < r1.args.length; i++) {
console.log("_dbg args[" + i + "]: " + r1.args[i].name + " value: " + r1.args[i].getGrounded());
}
} else {
console.log("_dbg has no args");
}
if(r1.rules.length > 0) {
} else {
console.log("_dbg has no body rules");
}
}
RuleEngine.dump_body_rules = function dump_body_rules() {
if(is_debug) {
console.log("_dbg dumping body rules");
for(var i = 0; i < RuleEngine.body_rules.length; i++) {
var bodyRule = RuleEngine.body_rules[i];
console.log("_dbg position: " + i + " bodyRule name: " + bodyRule.name + " is_context_change: " + bodyRule.is_context_change);
}
}
}
RuleEngine.dump_choices = function dump_choices() {
if(is_debug) {
console.log("_dbg dumping choices");
for(var i = 0; i < RuleEngine.choices.length; i++) {
var choice = RuleEngine.choices[i];
if(RuleEngine.getTypeName(choice) == 'Choice') {
console.log("_dbg position: " + i + " query name: " + choice.query.name + " rule name: " + choice.rule.name + " type: " + RuleEngine.getTypeName(choice));
console.log("_dbg choice.body_rules: ");
for(var l = 0; l < choice.body_rules.length; l++) {
var bodyRule = choice.body_rules[l];
console.log("_dbg position: " + l + " bodyRule name: " + bodyRule.name + " is_context_change: " + bodyRule.is_context_change);
}
} else {
console.log("_dbg position: " + i + " choice name: " + choice.name + " type: " + RuleEngine.getTypeName(choice));
}
}
}
}
RuleEngine.prototype.isQuerySolved = function (r_args) {
var is_solved = true;
if(is_debug) {
console.log("_dbg in isQuerySolved");
}
for(var i = 0; i < r_args.length; i++) {
if(!r_args[i].isGrounded()) {
if(is_debug) {
console.log("_dbg term: " + r_args[i].name + " is not grounded");
}
is_solved = false;
} else {
if(is_debug) {
console.log("_dbg term: " + r_args[i].name + " is grounded with value: " + r_args[i].getGrounded());
}
}
}
return is_solved;
};
RuleEngine.prototype.handleFindMoreSolutions = function (input_str) {
if(is_debug) {
console.log("_dbg in handleFireMoreSolutions");
}
RuleEngine.async_hold = false;
if(input_str == 'yes') {
var re = RuleEngine.getREInst();
re.backTrack();
} else {
if(RuleEngine.finished_cb) {
RuleEngine.finished_cb();
}
}
};
RuleEngine.prototype.handleQueryResult = function () {
if(is_debug) {
console.log("_dbg in handleQueryResult");
}
var q = RuleEngine.base_query;
var output_ar = [];
if(this.isQuerySolved(q.args)) {
if(RuleEngine.gnd_val_only) {
for(var i = 0; i < q.args.length; i++) {
output_ar.push(q.args[i].getGrounded());
}
} else {
output_ar.push('Query: ' + q.name + ' was solved, solutions are: \n');
for(var i = 0; i < q.args.length; i++) {
output_ar.push('arg name: ' + q.args[i].name + ' ground val: ' + q.args[i].getGrounded() + '\n');
}
}
} else {
if(RuleEngine.no_solutions_found_txt != '') {
output_ar.push(RuleEngine.no_solutions_found_txt);
} else {
output_ar.push('Query: ' + q.name + ' was not solved\n');
}
}
if(RuleEngine.choices.length > 0) {
if(is_debug) {
console.log("_dbg RuleEngine.choices.length: " + RuleEngine.choices.length);
}
output_ar.push('There are other possible solutions, should the solver continue?\n');
Util.output(output_ar.join(''));
output_ar = [];
RuleEngine.dump_choices();
if(RuleEngine.more_solutions_prompt == true) {
Util.input(this.handleFindMoreSolutions);
}
}
if(output_ar.length > 0) {
Util.output(output_ar.join(''));
}
};
return RuleEngine;
})();