Sixtest Wiki:API4/Parser

(function {	"use strict";	var extension = $API.create.extension("Parser");	extension.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; }; });