/** * @fileOverview MorphologyParser encapsulates the morphology parser for OshbRead. * @version 1.0 * @author David */ morphologyParser = function() { // Summary of Hebrew morphology codes. var morphCodes = { 'partOfSpeech': { 'A': 'Adjective', 'C': 'Conjunction', 'D': 'Adverb', 'N': 'Noun', 'P': 'Pronoun', 'R': 'Preposition', 'S': 'Suffix', 'T': 'Particle', 'V': 'Verb' }, 'adjectiveType': { 'a': 'adjective', 'c': 'cardinal number', 'g': 'gentilic', 'o': 'ordinal number', 'x': '' }, 'nounType': { 'c': 'common', 'g': 'gentilic', 'p': 'proper name', 'x': '' }, 'pronounType': { 'd': 'demonstrative', 'f': 'indefinite', 'i': 'interrogative', 'p': 'personal', 'r': 'relative', 'x': '' }, 'prepositionType': { 'd': 'definite article' }, 'suffixType': { 'd': 'directional he', 'h': 'paragogic he', 'n': 'paragogic nun', 'p': 'pronominal', 'x': '' }, 'particleType': { 'a': 'affirmation', 'd': 'definite article', 'e': 'exhortation', 'i': 'interrogative', 'j': 'interjection', 'm': 'demonstrative', 'n': 'negative', 'o': 'direct object marker', 'p': 'definite article with inseparable preposition', 'r': 'relative' }, 'verbStemHebrew': { 'q': 'qal', 'N': 'niphal', 'p': 'piel', 'P': 'pual', 'h': 'hiphil', 'H': 'hophal', 't': 'hithpael', 'o': 'polel', 'O': 'polal', 'r': 'hithpolel', 'm': 'poel', 'M': 'poal', 'k': 'palel', 'K': 'pulal', 'Q': 'qal passive', 'l': 'pilpel', 'L': 'polpal', 'f': 'hithpalpel', 'D': 'nithpael', 'j': 'pealal', 'i': 'pilel', 'u': 'hothpaal', 'c': 'tiphil', 'v': 'hishtaphel', 'w': 'nithpalel', 'y': 'nithpoel', 'z': 'hithpoel', 'x': '' }, 'verbStemAramaic': { 'q': 'peal', 'Q': 'peil', 'u': 'hithpeel', 'N': 'niphal', 'p': 'pael', 'P': 'ithpaal', 'M': 'hithpaal', 'a': 'aphel', 'h': 'haphel', 's': 'saphel', 'e': 'shaphel', 'H': 'hophal', 'i': 'ithpeel', 't': 'hishtaphel', 'v': 'ishtaphel', 'w': 'hithaphel', 'o': 'polel', 'z': 'ithpoel', 'r': 'hithpolel', 'f': 'hithpalpel', 'b': 'hephal', 'c': 'tiphel', 'm': 'poel', 'l': 'palpel', 'L': 'ithpalpel', 'O': 'ithpolel', 'G': 'ittaphal', 'x': '' }, 'verbAspect': { 'a': 'infinitive absolute', 'c': 'infinitive construct', 'h': 'cohortative', 'i': 'imperfect', 'j': 'jussive', 'p': 'perfect', 'q': 'sequential perfect', 'r': 'participle active', 's': 'participle passive', 'v': 'imperative', 'w': 'sequential imperfect', 'x': '' }, 'adjCase': { 'a': 'accusative', 'n': 'nominative', 'x': '' }, 'person': { '1': 'first person', '2': 'second person', '3': 'third person', 'x': '' }, 'gender': { 'b': 'both', 'c': 'common', 'f': 'feminine', 'm': 'masculine', 'x': '' }, 'number': { 'd': 'dual', 'p': 'plural', 's': 'singular', 'x': '' }, 'state': { 'a': 'absolute', 'c': 'construct', 'd': 'determined' }, 'language': { 'H': 'Hebrew', 'A': 'Aramaic' } }; // Parser for morphology codes. var MorphParse = function() { var language, nextName; /** * Parses the given code. * @param {string} code A morph code * @returns (string} The morphology */ this.Parse = function(code) { if (!code) {return {"morph": "", "next": "language", "segs": 0};} language = code.charAt(0); if (!morphCodes.language.hasOwnProperty(language)) { return {"morph": "Unknown language", "next": "error", "segs": 0}; } var morph = morphCodes.language[language]; code = code.substr(1); if (code) { var parts = code.split('/'), i = 1, len = parts.length; morph += ':
' + parseCode(parts[0]); for (; i < len; i++) { morph += '
' + parseCode(parts[i]); } } else { nextName = 'partOfSpeech'; } len = len ? len - 1 : 0; return {"morph": morph, "next": nextName, "segs": len}; }; // Parses the code. var parseCode = function(code) { if (!code) { nextName = 'partOfSpeech'; return ''; } var pos = code.charAt(0); if (!morphCodes.partOfSpeech.hasOwnProperty(pos)) { nextName = 'error'; return "Unknown part of speech"; } var morph = morphCodes.partOfSpeech[pos]; if (code.length > 1) { switch (pos) { case 'A': morph += ' ' + parseAdjective(code); break; case 'C': nextName = 'error'; morph += ' ' + "Unknown separator"; break; case 'D': nextName = 'error'; morph += ' ' + "Unknown separator"; break; case 'N': morph += ' ' + parseNoun(code); break; case 'P': morph += ' ' + parsePronoun(code); break; case 'R': morph += ' ' + parsePreposition(code); break; case 'S': morph += ' ' + parseSuffix(code); break; case 'T': morph += ' ' + parseParticle(code); break; case 'V': morph += ' ' + parseVerb(code); break; default: morph += ' Unknown part of speech in ' + code; } } else { switch (pos) { case 'A': nextName = 'adjectiveType'; break; case 'C': nextName = 'separator'; break; case 'D': nextName = 'separator'; break; case 'N': nextName = 'nounType'; break; case 'P': nextName = 'pronounType'; break; case 'R': nextName = 'prepositionType'; break; case 'S': nextName = 'suffixType'; break; case 'T': nextName = 'particleType'; break; case 'V': if (language === 'H') { nextName = 'verbStemHebrew'; } else { nextName = 'verbStemAramaic'; } break; default: nextName = 'error'; } } return morph; }; // Parses the adjective code. var parseAdjective = function(code) { if (!morphCodes.adjectiveType.hasOwnProperty(code.charAt(1))) { nextName = 'error'; return "Unknown adjective type"; } var morph = morphCodes.adjectiveType[code.charAt(1)]; if (code.length > 2) { morph += ' ' + parseGender(code, 2); } else { nextName = 'gender'; } return morph; }; // Parses the noun code. var parseNoun = function(code) { if (!morphCodes.nounType.hasOwnProperty(code.charAt(1))) { nextName = 'error'; return "Unknown noun type"; } var morph = morphCodes.nounType[code.charAt(1)]; if (code.length > 2) { morph += ' ' + parseGender(code, 2); } else { nextName = 'gender'; } return morph; }; // Parses the pronoun code. var parsePronoun = function(code) { if (!morphCodes.pronounType.hasOwnProperty(code.charAt(1))) { nextName = 'error'; return "Unknown pronoun type"; } var morph = morphCodes.pronounType[code.charAt(1)]; if (code.length > 2) { morph += ' ' + parsePerson(code, 2); } else { nextName = 'person'; } return morph; }; // Parse the preposition code. var parsePreposition = function(code) { if (!morphCodes.prepositionType.hasOwnProperty(code.charAt(1))) { nextName = 'error'; return "Unknown preposition type"; } var morph = morphCodes.prepositionType[code.charAt(1)]; if (code.length > 2) { nextName = 'error'; return "Unknown separator"; } else { nextName = 'separator'; } return morph; }; // Parses the suffix code. var parseSuffix = function(code) { if (!morphCodes.suffixType.hasOwnProperty(code.charAt(1))) { nextName = 'error'; return "Unknown suffix type"; } var morph = morphCodes.suffixType[code.charAt(1)]; if (code.length > 2) { morph += ' ' + parsePerson(code, 2); } else { nextName = 'person'; } return morph; }; // Parses the participle code. var parseParticle = function(code) { if (!morphCodes.particleType.hasOwnProperty(code.charAt(1))) { nextName = 'error'; return "Unknown particle type"; } var morph = morphCodes.particleType[code.charAt(1)]; if (code.length > 2) { nextName = 'error'; return "Unknown separator"; } else { nextName = 'separator'; } return morph; }; // Parses the verb code. var parseVerb = function(code) { var morph, isMorph; if (language === 'H') { isMorph = morphCodes.verbStemHebrew.hasOwnProperty(code.charAt(1)); morph = morphCodes.verbStemHebrew[code.charAt(1)]; } else { isMorph = morphCodes.verbStemAramaic.hasOwnProperty(code.charAt(1)); morph = morphCodes.verbStemAramaic[code.charAt(1)]; } if (!isMorph) { nextName = 'error'; return "Unknown verb stem"; } if (code.length > 2) { morph += ' ' + parseAspect(code); } else { nextName = 'verbAspect'; } return morph; }; // Parses the aspect code. var parseAspect = function(code) { if (!morphCodes.verbAspect.hasOwnProperty(code.charAt(2))) { nextName = 'error'; return "Unknown verb aspect"; } var morph = morphCodes.verbAspect[code.charAt(2)]; if (morph === 'participle active' || morph === 'participle passive') { if (code.length > 3) { morph += ' ' + parseGender(code, 3); } else { nextName = 'gender'; } } else if (morph === 'infinitive absolute' || morph === 'infinitive construct') { if (code.length > 3) { nextName = 'error'; return "Unknown field"; } else { nextName = 'separator'; } } else { if (code.length > 3) { morph += ' ' + parsePerson(code, 3); } else { nextName = 'person'; } } return morph; }; // Parses the person code. var parsePerson = function(code, pos) { if (!morphCodes.person.hasOwnProperty(code.charAt(pos))) { nextName = 'error'; return "Unknown person"; } var morph = morphCodes.person[code.charAt(pos)]; pos++; if (code.length > pos) { morph += ' ' + parseGender(code, pos); } else { nextName = 'gender'; } return morph; }; // Parses the gender code. var parseGender = function(code, pos) { if (!morphCodes.gender.hasOwnProperty(code.charAt(pos))) { nextName = 'error'; return "Unknown gender"; } var morph = morphCodes.gender[code.charAt(pos)]; pos++; if (code.length > pos) { morph += ' ' + parseNumber(code, pos); } else { nextName = 'number'; } return morph; }; // Parses the number code. var parseNumber = function(code, pos) { if (!morphCodes.number.hasOwnProperty(code.charAt(pos))) { nextName = 'error'; return "Unknown number"; } var morph = morphCodes.number[code.charAt(pos)]; pos++; if (code.length > pos) { morph += ' ' + parseState(code, pos); } else if (code.charAt(0) === 'V') { if (code.charAt(2) === 'r' || code.charAt(2) === 's') { nextName = 'state'; } else { nextName = 'separator'; } } else if (code.charAt(0) === 'P' || code.charAt(0) === 'S') { nextName = 'separator'; } else { nextName = 'state'; } return morph; }; // Parses the state code. var parseState = function(code, pos) { if (!morphCodes.state.hasOwnProperty(code.charAt(pos))) { nextName = 'error'; return "Unknown state"; } var morph = morphCodes.state[code.charAt(pos)]; pos++; if (code.length > pos) { nextName = 'error'; return "Unknown separator"; } else { nextName = 'separator'; } return morph; }; }; // An instance of MorphParse. var parser = new MorphParse; // Return the public interface. return function(code) { return parser.Parse(code); } }();