ritajs-v2 icon indicating copy to clipboard operation
ritajs-v2 copied to clipboard

Grammars in Twine

Open dhowe opened this issue 3 years ago • 8 comments

I'd like to support the following two types of grammar cases (with and without closing tag). Can you see if this is possible?

<<rg $rules >>

<<rg>>
{
  rules
}
<</rg>>

dhowe avatar Mar 19 '21 13:03 dhowe

I think this <<rg $rules>> <<rg>>{}<</rg>> is not possible at least in sugarCube... coz a Macro is either self-closing or have closing tag, and there can't be two Marcos of the same name

it is possible to have something like this <<rg $rules>> <<rg {"start":"a"}>> //must be a valid json object without line break //or <<rg '{ start: "a" }'>> //can be json or js object and have line-breaker, but must pass in as a string

Real-John-Cheung avatar Mar 19 '21 15:03 Real-John-Cheung

ok, can you include (either here or in a notebook) the simplest possible code for a <<rg>> macro as below:

<<rg>>{start: $rule1, ... }<</rg>>

<<rg>>$rules<</rg>>

and also with an optional start rule:

<<rg 'optionalStartRuleName'>>$rules<</rg>>

where rules is either a literal JS object, or a previously declared twine variable no need for JSON unless it is an external .json file (not sure how this works in twine)

note: the only added benefit of doing this, over what what he have now, is that we can pass State.variables to grammar.expand automatically

dhowe avatar Mar 23 '21 09:03 dhowe

https://observablehq.com/@real-john-cheung/riscript-and-rigrammar-in-twine rules can be a literal JS object, a json object or a twine variable

setup.JSLoaded = false;
setup.lockID = LoadScreen.lock();
function parseObject (obj) {
  return Function('"use strict";return (' + obj + ')')();
}
importScripts("https://unpkg.com/rita").then(function () {
  Macro.add('rg',{
   skipArgs: false,
   tags: null,
   handler: function () {
     let s = this.payload[0].contents.trim();
     let o;
     try {
        o = JSON.parse(s);
     } catch(e) {
     }
     if (!o) {
        try {
           o = parseObject(s);
        } catch {
        }
     }
     if (!o && /^\$[A-Za-z0-9$_]+$/.test(s)){
	 s = s.replace('$','');
	 o = State.variables[s] ? State.variables[s] : undefined;
     }
     if (!o) throw Error("fail to parse grammar, " + s + " is not a vaild object.");
     $(this.output).wiki(RiTa.grammar(o).expand(this.args[0],State.variables));
   }
  });
  setup.JSLoaded = true;
  Engine.play(passage(), true);
  LoadScreen.unlock(setup.lockID);
}).catch(function (err) {
  alert(err);
});

Real-John-Cheung avatar Mar 23 '21 13:03 Real-John-Cheung

the grammar() function already accepts json and js objects, no? why parse them separately ?

dhowe avatar Mar 23 '21 14:03 dhowe

because what inside Macro.playload.contents is string, so it need to be parsed into object

grammar() actually can take in JSON string but literal jsobject string need to parsed first

Real-John-Cheung avatar Mar 23 '21 14:03 Real-John-Cheung

so we don't need JSON.parse in there, correct?

dhowe avatar Mar 30 '21 12:03 dhowe

We don't need it (i.e. we can code another (I think will be more complex) version that do the same without it) but maybe we should keep the JSON.parse() because we don't want to pass a random(unchecked) string into grammar(), and with it we can make sure that the type of the parameter pass in grammar() is always object.

Real-John-Cheung avatar Apr 07 '21 14:04 Real-John-Cheung

sounds good, reassigning to myself

dhowe avatar Apr 07 '21 14:04 dhowe