renpy-js
Version:
renpy parser for javascript
153 lines (136 loc) • 4.78 kB
JavaScript
import RenpyCharacter from "./components/RenpyCharacter";
import Renpy from "./components/Renpy";
import RenpyCommand from "./components/RenpyCommand";
export default class RenpyParser {
constructor() {
this.config = {
characters: [],
images: []
};
this.labels = [];
this.commands = [];
this.mode = 'COMMAND'; // ['COMMAND', 'MENU', 'INIT']
this.currentMenu = null;
this.currentMenuSelection = '';
this.currentLabel = '';
}
parseRenpyFile(file) {
let lines = file.split('\r\n');
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
if (RenpyParser._isUselessLine(line)) {
continue;
}
if (RenpyParser._isIndentedLine(line)) {
this._followMode(line);
} else { // not indented line
this._setNewMode(line);
}
}
if (this._isMenuModeBefore()) {
this.endMenuMode();
}
return new Renpy(this.config, this.labels, this.commands);
}
_followMode(line) {
line = line.trim();
// indented line follows before mode
if (this.mode === 'COMMAND') {
this.commands[this.currentLabel].push(this._parseCommand(line));
} else if (this.mode === 'MENU') {
this._parseMenu(line);
}
}
_setNewMode(line) {
line = line.trim();
// find new mode
if (this._isMenuModeBefore()) {
this.endMenuMode();
}
if (RenpyParser._isLabelLine(line)) {
this.mode = 'COMMAND';
let labelKey = line.split(" ")[1].replace(":", "");
this.labels.push(labelKey);
this.commands[labelKey] = [];
this.currentLabel = labelKey;
} else if (line.startsWith('menu')) {
this.mode = 'MENU';
this.currentMenu = new RenpyCommand('menu');
} else if (RenpyParser._isInitLine(line)) {
this.mode = 'INIT';
this._parseConfig(line);
}
}
_parseCommand(line) {
let args = line.split(" ");
let type = args[0];
if (Object.keys(this.config.characters).includes(type) || Object.keys(this.config).includes(type)) {
let i = line.indexOf(" ");
let say = line.slice(i + 1);
return new RenpyCommand(type, say);
} else {
args.splice(args, 1);
return new RenpyCommand(type, ...args);
}
}
_parseMenu(line) {
if (RenpyParser._isQuotedLine(line)) {
this.currentMenuSelection = line.replace(":", "");
} else {
this.currentMenu.target[this.currentMenuSelection] = this._parseCommand(line);
}
}
_parseConfig(line) {
let args = line.split(" ");
let type = args[0];
switch (type) {
case 'define':
if (args[3].startsWith('Character')) {
let characterDef = args[1];
let parseLeft = args[3].split('(');
let param;
if (parseLeft[1] === ')') {
param = "''";
} else {
param = parseLeft[1].split(')')[0];
}
let params = [];
if (param.indexOf(",") >= 0) {
params = [param.split(",")[0], args[4].split('"')[1]];
} else {
params = [param];
}
this.config.characters[characterDef] = new RenpyCharacter(...params);
} else {
let defKey = args[1];
this.config[defKey] = args[3];
}
break;
case 'image':
break;
}
}
static _isInitLine(line) {
return line.startsWith('image') || line.startsWith('define');
}
static _isLabelLine(line) {
return line.startsWith('label');
}
static _isUselessLine(line) {
return line.trim().startsWith('#') || line.trim() === "";
}
static _isQuotedLine(line) {
return line.startsWith('"');
}
static _isIndentedLine(line) {
return line.startsWith(' ');
}
_isMenuModeBefore() {
return this.mode === 'MENU';
}
endMenuMode() {
this.commands[this.currentLabel].push(this.currentMenu);
this.currentMenu = null;
this.currentMenuSelection = '';
}
}