Skip to content

Commit

Permalink
set this.context in transforms
Browse files Browse the repository at this point in the history
  • Loading branch information
dhowe committed Jan 28, 2024
1 parent 7b2bd65 commit 6eac922
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 71 deletions.
88 changes: 44 additions & 44 deletions src/visitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ class BaseVisitor {
class RiScriptVisitor extends BaseVisitor {
constructor(riScript, context = {}) {
super(riScript);
this.context = context;

this.order = 0;
this.trace = 0;
this.indent = 0;
this.choices = {};
this.context = context;
this.isNoRepeat = false;

this.Symbols = this.scripting.Symbols;
Expand Down Expand Up @@ -624,45 +624,6 @@ class RiScriptVisitor extends BaseVisitor {
return value;
}

// value is not yet resolved, so store with transform for later
restoreTransforms(value, txs) {
if (typeof value === 'string') {
const choiceRE = new RegExp('^' + this.Escaped.OPEN_CHOICE + '.*' + this.Escaped.CLOSE_CHOICE + '$');
const symbolRE = new RegExp(`(${this.Escaped.DYNAMIC}|${this.Escaped.STATIC}[A-Za-z_0-9])[A-Za-z_0-9]*`);
if (!choiceRE.test(value) && !symbolRE.test(value)) {
// wrap in choice to preserve
value = this.Symbols.OPEN_CHOICE + value + this.Symbols.CLOSE_CHOICE;
}
if (txs) {
txs.forEach((tx) => (value += tx.image)); // append transform strings
}
if (this.traceTx) console.log('restoreTransforms:', value);
}
return value;
}

castValues(obj) {
let madeCast = false;
Object.entries(obj).forEach(([k, v]) => {
const num = parseFloat(v);
if (!isNaN(num)) {
madeCast = true;
obj[k] = num; // update object with casted value
}
});
return madeCast;
}

contextIsResolved(table) {
let allResolved = true;
Object.entries(table).forEach(([key, val]) => {
if (!this.scripting.isParseable(val)) {
allResolved = false;
}
});
return allResolved;
}

applyTransform(target, transform) {

const image = transform.image;
Expand All @@ -675,19 +636,19 @@ class RiScriptVisitor extends BaseVisitor {

// function in dynamics
if (typeof this.dynamics[tx] === 'function') {
result = this.dynamics[tx].call(this.scripting, target);
result = this.dynamics[tx].bind(this.context)(target);
}
// function in statics
else if (typeof this.statics[tx] === 'function') {
result = this.statics[tx].call(this.scripting, target);
result = this.statics[tx].call(this.context, target);
}
// function in context
else if (typeof this.context[tx] === 'function') {
result = this.context[tx].call(this.scripting, target);
result = this.context[tx].call(this.context, target);
}
// function in transforms
else if (typeof this.scripting.transforms[tx] === 'function') {
result = this.scripting.transforms[tx].call(this.scripting, target);
result = this.scripting.transforms[tx].call(this.context, target);
}
// member functions (usually on String)
else if (typeof target[tx] === 'function') {
Expand All @@ -712,6 +673,45 @@ class RiScriptVisitor extends BaseVisitor {
return result;
}

// value is not yet resolved, so store with transform for later
restoreTransforms(value, txs) {
if (typeof value === 'string') {
const choiceRE = new RegExp('^' + this.Escaped.OPEN_CHOICE + '.*' + this.Escaped.CLOSE_CHOICE + '$');
const symbolRE = new RegExp(`(${this.Escaped.DYNAMIC}|${this.Escaped.STATIC}[A-Za-z_0-9])[A-Za-z_0-9]*`);
if (!choiceRE.test(value) && !symbolRE.test(value)) {
// wrap in choice to preserve
value = this.Symbols.OPEN_CHOICE + value + this.Symbols.CLOSE_CHOICE;
}
if (txs) {
txs.forEach((tx) => (value += tx.image)); // append transform strings
}
if (this.traceTx) console.log('restoreTransforms:', value);
}
return value;
}

castValues(obj) {
let madeCast = false;
Object.entries(obj).forEach(([k, v]) => {
const num = parseFloat(v);
if (!isNaN(num)) {
madeCast = true;
obj[k] = num; // update object with casted value
}
});
return madeCast;
}

contextIsResolved(table) {
let allResolved = true;
Object.entries(table).forEach(([key, val]) => {
if (!this.scripting.isParseable(val)) {
allResolved = false;
}
});
return allResolved;
}

lookupsToString() {
const dyns = {}, stats = {};
Object.entries(this.dynamics || {}).forEach(([k, v]) => (dyns[`$${k}`] = v));
Expand Down
112 changes: 89 additions & 23 deletions test/grammar.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe(title, function () {
});

describe('Characters', function () {
it('Handles character choice in context', function () {
it('Handles character choice in context', function () {
let context, script, res;

// simple case
Expand Down Expand Up @@ -116,32 +116,98 @@ describe(title, function () {
expect(res).to.be.oneOf(['Lucy', 'Sam']);
});

LTR && it('Should reference context from transforms', function () {
const context = {
characters: [{
name: 'Lucy',
pronoun: 'she',
car: 'Acura'
it('Should reference context from transforms', function () {
let ctx, rules, res;
ctx = {
prop: 42,
func: function () {
return this.prop;
},
{
name: 'Sam',
pronoun: 'he',
car: 'Subaru'
}],
chooseChar: function () {
console.log('chooseChar:', typeof this);
let chars = this.visitor.context.characters;
return chars[Math.floor(Math.random() * chars.length)];
};
rules = { start: "$.func" }
res = RiGrammar.expand(rules, ctx);
expect(res).eq('42');

ctx = {
prop: { num: 42 },
func: function () {
return this.prop.num;
},
};
rules = { start: "$.func" }
res = RiGrammar.expand(rules, ctx);
expect(res).eq('42');

ctx = {
prop: { num: 42 },
func: function () {
return this.prop;
},
};
rules = { start: "$.func.num" }
res = RiGrammar.expand(rules, ctx);
expect(res).eq('42');

ctx = {
char: { name: 'bill', age: 42 },
func: function () {
return this.char;
},
};
rules = { start: "{$chosen=$.func} $chosen.name is $chosen.age years old" }
res = RiGrammar.expand(rules, ctx);
expect(res).eq('bill is 42 years old');

ctx = {
chars: [{ name: 'bill', age: 42 }, { name: 'dave', age: 43 }],
func: function () {
return this.chars[Math.floor(Math.random() * this.chars.length)];
},
};
rules = { start: "{#chosen=$.func} $chosen.name is $chosen.age years old" }
res = RiGrammar.expand(rules, ctx);
expect(res).to.be.oneOf([
'bill is 42 years old',
'dave is 43 years old',
]);

ctx = {
chars: [{ name: 'bill', age: 42 }, { name: 'dave', age: 43 }],
func: function () {
return this.chars[Math.floor(Math.random() * this.chars.length)];
},
};
rules = { start: "{#chosen=$.func} $sent", sent: "$chosen.name is $chosen.age years old" }
res = RiGrammar.expand(rules, ctx);
expect(res).to.be.oneOf([
'bill is 42 years old',
'dave is 43 years old',
]);

ctx = {
characters: [
{
name: 'Lucy',
pronoun: 'she',
car: 'Acura'
},
{
name: 'Sam',
pronoun: 'he',
car: 'Subaru'
}
],
subject: function () {
return this.characters[Math.floor(Math.random() * this.characters.length)];
}
}
const rules = {
start: "{$person=$chooseChar()} $sentence",
sentence: "$Meet $person.name. $person.pronoun.cap() drives $person.car",
"#person": "$sam | $lucy"
rules = {
start: "{#person=$.subject()} $sentence",
sentence: "Meet $person.name. $person.pronoun.cap() drives $person.car.art().",
}
let result = RiGrammar.expand(rules, context);
expect(result).to.be.oneOf([
'Meet Lucy. She drives a Acura.',
res = RiGrammar.expand(rules, ctx);
expect(res).to.be.oneOf([
'Meet Lucy. She drives an Acura.',
'Meet Sam. He drives a Subaru.',
]);
});
Expand Down
8 changes: 4 additions & 4 deletions test/riscript.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -987,10 +987,10 @@ describe(title, function () {
});


it('Pass scripting as this', function () {
it('Pass context as this', function () {
let checkThis = function (word) {
expect(this).eq(riscript);
return word + (this == riscript ? ' success' : ' failure');
expect(this).eq(riscript.visitor.context);
return word + (this === riscript.visitor.context ? ' success' : ' failure');
}
let res = riscript.evaluate('[hello].checkThis', { checkThis });
expect(res).eq('hello success');
Expand Down Expand Up @@ -1120,7 +1120,7 @@ describe(title, function () {
expect(res).eq('The dog.rhymes');

let addRhyme2 = function (word) {
return word + ' rhymes with bog' + this.RiTa.randi(1);
return word + ' rhymes with bog' + riscript.RiTa.randi(1);
}
expect(riscript.transforms.rhymes2).is.undefined;
riscript.addTransform('rhymes2', addRhyme2);
Expand Down

0 comments on commit 6eac922

Please sign in to comment.