Sixtest Wiki:API5/Parser

(function {	"use strict";	$API("Project:API5/Parser", function (parser) { console.log("parser:args:",arguments); parser.extend({			parse: function (input, add) {				var mode, tokens, str, c, subj, arr, parsed, len, i, callParserFunc, subjA, carr, restoreDefaults, j = 0, lenj, data, itemID = {}, currid, result = [], param, trim;				mode = {					name: false,					group: false,					param: false,					nameArr: false,					propertyArr: false,					valueArr: false,					property: false,					trim: true,					value: false,					quote: false,					barvar: false				};				tokens = [];				str = '';				subj = {};				subjA = {};				arr = [];				parsed = [];				carr = [];				len = input.length;				i = 0;				trim = function (str) {					/*jslint regexp: true */					var re = /\s*(.+?)\s*$/;					/*jslint regexp: false */					return (str.match(re) || [])[1];				};				restoreDefaults = function {					mode = {						name: false,						group: false,						param: false,						nameArr: false,						propertyArr: false,						valueArr: false, property: false, trim: true, value: false, quote: false, barvar: false };				};				tokens = [ {						name: "OPEN_GROUP", token: "{", func: function { // enter group mode mode.group = true; // arr is the 1st level of the group. // arr should be edited by: // sounds: [ "MsgA", "MsgB", "MsgC" ]; // droppedby: [ "Rat", "Cave Rat" ]; if (arr.length === 0) { subj.value = arr; }							if (str !== '') { // if a string comes before the group, add it to the array // (why are we doing this again?) arr[arr.length] = str; str = ''; }							// errr... sounds and droppedby don't use this format, so it shouldn't be here ... // arr[arr.length] = carr; mode.trim = true; }					},					{						name: "WHITESPACE", token: " ", func: function { // trim whitespace if in trim mode if (!mode.trim || str) { str += c;							} }					},					{						name: "DOT", token: ".", func: function { // dot changes mode from property to name // don't do it if the mode property is not active if (mode.property) { // we're done with editing the property, so set property = str; subj.property = str; // reset str str = ''; // trim mode because names are allowed to have spaces mode.trim = false; // now edit the name mode.name = true; // no longer in property mode mode.property = false; } else { str += c;							} }					},					{						name: "COLON", token: ":", func: function { if (mode.group && mode.barvar) { subjA.name = trim(str); str = ''; mode.nameArr = false; mode.valueArr = true; } else { str += c;							} }					},					{						name: "COMMA", token: ",", func: function { // the comma changes from name -> value // only if in group mode, and not in literal mode if (mode.group && !mode.quote) { if (mode.barvar) { // dealing with convention {|a,b;c} subjA.name = trim(str); str = ''; mode.nameArr = false; mode.valueArr = true; } else { // dealing with convention { "a", "b", "c" } if (str !== '') { arr[arr.length] = str; str = ''; // whitespace should be trimmed until the next "										mode.trim = true;									}								}							} else {								str += c;							}						}					},					{						name: "SEMICOLON",						token: ";",						func: function {							if (mode.group && mode.barvar) {								// semicolon changes mode from nameArr or valueArr to propertyArr								// only if in group & not sounds !(!barvar)								if (mode.valueArr || mode.nameArr) {									if (mode.valueArr) {										subjA.value = str;										str = ;									} else {										subjA.name = trim(str);										str = ;									}									mode.propertyArr = true;									mode.valueArr = mode.nameArr = false;								}							} else {								str += c;							}						}					},					{						name: "QUOTE",						token: "\"", func: function { // change to literal mode mode.quote = !mode.quote; // literal mode = no trimming mode.trim = !mode.quote; }					},					{						name: "BAR", token: "|", func: function { // bar starts a new variable = trim mode mode.trim = true; // here's where it gets confusing ... // if we're in a group the behavior is different if (mode.group) { // in group mode, | separates items, but only if using the 'trade convention' // format is: { |item1, value1, meta1 |... }								if (str !== '') { if (mode.propertyArr) { subjA.property = str; str = ''; } else if (mode.valueArr) { subjA.value = str; str = ''; } else { subjA.name = trim(str); str = ''; }								} else if (mode.nameArr) { subjA.name = trim(str); str = ''; }								if (subjA.name || subjA.value || subjA.property) { arr[arr.length] = subjA; }								subjA = {}; mode.propertyArr = mode.valueArr = false; mode.nameArr = mode.barvar = true; mode.trim = false; } else { if (str !== '') { if (mode.value) { subj.value = str; str = ''; } else { subj.name = str; str = ''; }								}								mode.value = false; if (subj.name || subj.value) { parsed[parsed.length] = subj; str = ''; subj = {}; }								// restore defaults restoreDefaults; mode.property = true; }						}					},					{						name: "EQUALS", token: "=", func: function { if (!mode.group) { mode.trim = false; if (mode.name) { mode.name = false; mode.value = true; subj.name = str; str = ''; } else { mode.property = false; mode.value = true; subj.property = str; str = ''; }							} else { str += c;							} }					},					{						name: "CLOSE_GROUP", token: "}", func: function { if (!mode.barvar) { // for sounds etc.								arr[arr.length] = trim(str); subj.value = arr; str = ''; arr = []; } else { // for trades etc.								if (mode.nameArr) { subjA.name = trim(str); } else if (mode.valueArr) { subjA.value = trim(str); } else if (mode.propertyArr) { subjA.property = trim(str); }								str = ''; arr[arr.length] = subjA; carr = []; arr = []; subjA = {}; mode.barvar = false; }							mode.nameArr = mode.valueArr = mode.propertyArr = mode.group = false; }					},					{						name: "END_OF_FILE", token: "_EOF_", func: function { /*							if (subj.name || subj.value || subj.property) { parsed[parsed.length] = subj; subj = {}; str = ''; }							*/						}					}				];				callParserFunc = function (array, property, value) { var len = array.length, i = 0; for (i; i < len; i += 1) { if (array[i][property] === value) { array[i].func; return true; }					}					return false; };				for (i; i < len; i += 1) { c = input.charAt(i); if (!callParserFunc(tokens, 'token', c)) { str += c;					} }				callParserFunc(tokens, 'token', '|'); if (str !== '') { if (mode.property) { subj.property = str; } else if (mode.value) { if (subj.value.length) { subj.value[subj.value.length] = str; } else { subj.value = str; }					} else if (mode.name) { subj.name = str; }					str = ''; parsed[parsed.length] = subj; subj = {}; }				lenj = parsed.length; for (j; j < lenj; j += 1) { data = parsed[j]; if (data.name) { currid = itemID[data.name]; if (currid === undefined) { currid = itemID[data.name] = result.length; result[currid] = { "name": data.name, "id": currid }; if (add) { for (param in add) { if (add.hasOwnProperty(param)) { result[currid][param] = add[param]; }								}							}						}						if (data.property && data.value) { result[currid][data.property] = data.value; }					}				}				return result; }		});	}); });