Best Python code snippet using molotov_python
syntax.py
Source:syntax.py  
1# -*- coding: utf-8 -*-2"""3Hymmnoserver module: common.syntax4Purpose5=======6 Processes Hymmnos, producing syntax trees upon sucess.7 8Details9=======10 This module implements a forward-only recursive descent parser.11 12 This means that the first successful match is considered correct; doing this13 was a decision based on the fact that Hymmnos is largely linear in nature, and14 only truly exceptional cases actually need backtracking. For those, it should15 suffice to craft an especially detailed AST and place it before the more16 general entries, thus saving vast amounts of processing power without17 significantly reducing coverage of the language's syntactic structures.18 19Legal20=====21 All code, unless otherwise indicated, is original, and subject to the terms of22 the GNU GPLv3 or, at your option, any later version of the GPL.23 24 All content is derived from public domain, promotional, or otherwise-compatible25 sources and published uniformly under the26 Creative Commons Attribution-Share Alike 3.0 license.27 28 See license.README for details.29 30 (C) Neil Tallim, 200931"""32import cgi33import re34import urllib35import xml.dom.minidom36import lookup37_ANY = 0 #: An AST classifier that requires zero-or-more matches from its set.38_ALL = -1 #: An AST classifier that requires every set member to match.39_ONE = 1 #: An AST classifier that requires at least one member to match. (Successive matches are ignored)40_LEX_ADJ = 8 #: A symbolic constant identifying adjectives.41_LEX_ADV = 3 #: A symbolic constant identifying adverbs.42_LEX_CNSTR = 18 #: A symbolic constant identifying language constructs.43_LEX_CONJ = 5 #: A symbolic constant identifying conjunctions.44_LEX_ESi = 14 #: A symbolic constant identifying Emotion Sound Is.45_LEX_ESii = 7 #: A symbolic constant identifying Emotion Sound IIs.46_LEX_ESiii = 13 #: A symbolic constant identifying Emotion Sound IIIs.47_LEX_EV = 1 #: A symbolic constant identifying Emotion Verbs.48_LEX_INTJ = 16 #: A symbolic constant identifying interjections.49_LEX_N = 4 #: A symbolic constant identifying nouns.50_LEX_PREP = 6 #: A symbolic constant identifying prepositions.51_LEX_PRON = 15 #: A symbolic constant identifying pronouns.52_LEX_PRT = 12 #: A symbolic constant identifying particles.53_LEX_V = 2 #: A symbolic constant identifying verbs.54_DLCT_UNKNOWN = 0 #: A symbolic constant identifying unknown words.55_DLCT_CENTRAL = 1 #: A symbolic constant identifying Central words.56_DLCT_CULT_CIEL = 2 #: A symbolic constant identifying Cult Ciel words.57_DLCT_CLUSTER = 3 #: A symbolic constant identifying Cluster words.58_DLCT_ALPHA = 4 #: A symbolic constant identifying Alpha words.59_DLCT_METAFALSS = 5 #: A symbolic constant identifying Metafalss words.60_DLCT_PASTALIE = 6 #: A symbolic constant identifying Pastalie words.61_DLCT_ALPHA_EOLIA = 7 #: A symbolic constant identifying EOLIA words.62_DIALECT_SHIFT = 50 #: The constant value that determines the spacing between dialect variants.63_EXACT_MATCH_REGEXP = re.compile(r"^[a-z.]+\$\d+$") #: A regular expression used to determine whether an AST element is an exact-match specifier.64_GENERAL_AST = (_ALL,65 (_ANY, _LEX_CONJ, _LEX_INTJ, _LEX_PREP),66 (_ANY,67  'ESP',68  (_ALL,69   (_ONE,70    (_ALL, 'VsP', 'SgP', 'VP'),71    (_ALL, 'SgP', 'VP'),72    (_ALL, 'VsP', 'VP'),73    'VP',74    'SgP',75   ),76   (_ANY, (_ALL, _LEX_CONJ, 'SgsP'))77  )78 ),79 (_ANY, 'CgP'),80 (_ANY, 'AaP'),81 (_ANY, _LEX_INTJ)82) #: The AST that describes standard Hymmnos.83_PASTALIE_AST = (_ALL,84 (_ANY, _LEX_CONJ, _LEX_INTJ, _LEX_PREP),85 (_ONE,86  (_ALL, 'NsP', _LEX_CONJ, 'SpP', 'EVP'),87  (_ALL,88   'SevmP',89   (_ANY,90    (_ONE,91     (_ALL, _LEX_CONJ, 'SevP'),92     'VP',93     'EVP'94    )95   )96  ),97  (_ALL,98   (_ONE, 99    (_ALL,100     (_ONE,101      'SevnP',102      'EVhP'103     ),104    ),105    (_ANY, 'SpP')106   ),107   (_ANY, (_ONE, 'EVP', 'VP')),108   (_ANY, (_ALL, _LEX_CONJ, 'SevP'))109  ),110  (_ALL,111   _LEX_PRON,112   'EVP'113  )114 ),115 (_ANY, 'CpP'),116 (_ANY, 'AaP'), 117 (_ANY, _LEX_INTJ)118) #: The AST that describes Pastalie Hymmnos.119_AST_FRAGMENTS = {120 'AaP': (_ALL,121  (_ONE, _LEX_ADV, _LEX_ADJ),122  (_ANY, 'AalP')123 ),124 'AalP': (_ALL,125  (_ONE, _LEX_ADV, _LEX_ADJ),126  (_ANY, 'AalP')127 ),128 'AavP': (_ALL,129  _LEX_ADV,130  (_ANY, 'AavlP')131 ),132 'AavlP': (_ALL,133  _LEX_ADV,134  (_ANY, 'AavlP')135 ),136 'AnP': (_ALL,137  (_ONE, _LEX_ADJ, _LEX_ADV, _LEX_PRON),138  (_ANY, 'AnlP'),139  (_ANY, (_ALL, _LEX_CONJ, 'AnP'))140 ),141 'AnlP': (_ALL,142  (_ONE, _LEX_ADJ, _LEX_ADV),143  (_ANY, 'AnlP'),144  (_ANY, (_ALL, _LEX_CONJ, 'AnP'))145 ),146 'AnpP': (_ALL,147  (_ONE, _LEX_ADJ, _LEX_ADV),148  (_ANY, 'AnplP'),149  (_ANY, (_ALL, _LEX_CONJ, 'AnpP'))150 ),151 'AnplP': (_ALL,152  (_ONE, _LEX_ADJ, _LEX_ADV),153  (_ANY, 'AnplP'),154  (_ANY, (_ALL, _LEX_CONJ, 'AnpP'))155 ),156 'AvP': (_ALL,157  (_ONE, _LEX_ADJ, _LEX_ADV, _LEX_PRON),158  (_ANY, 'AvlP'),159  (_ANY, (_ALL, _LEX_CONJ, 'AvP'))160 ),161 'AvlP': (_ALL,162  (_ONE, _LEX_ADJ, _LEX_ADV),163  (_ANY, 'AvlP'),164  (_ANY, (_ALL, _LEX_CONJ, 'AvP'))165 ),166 'CgP': (_ONE,167  'NP',168  (_ALL,169   'VP',170   (_ANY, 'NP'),171   (_ANY, 'CgP')172  )173 ),174 'CpP': (_ONE,175  'NP',176  (_ALL,177   (_ONE, 'VP', 'EVP'),178   (_ANY, 'NP'),179   (_ANY, 'CpP')180  )181 ),182 'ESP': (_ALL, _LEX_ESi, _LEX_ESii, _LEX_ESiii),183 'EVNP': (_ALL,184  (_ANY, _LEX_PRON),185  (_ANY, 'AvP'),186  _LEX_EV,187  (_ANY, 'AavP'),188  (_ANY,189   (_ALL,190    (_ANY, (_ONE, _LEX_PREP, _LEX_PRT)),191    (_ONE,192     (_ONE,193      (_ALL, 'TP', 'TP'),194      'TP'195     ),196     'EVOP',197     'EVNP'198    ),199    (_ANY, 'PP')200   )201  ),202 ),203 'EVOP': (_ALL,204  'x.$%i' % (_DLCT_PASTALIE),205  (_ONE,206   (_ALL,207    (_ANY, 'rre$%i' % (_DLCT_CENTRAL)),208    (_ONE,209     _LEX_PRON,210     (_ALL, _LEX_EV, (_ANY, 'AavP'))211    )212   ),213   (_ALL, 'rre$%i' % (_DLCT_CENTRAL), 'NP')214  ),215  'EVP'216 ),217 'EVP': (_ALL,218  (_ANY, _LEX_PRON),219  (_ANY, 'AvP'),220  _LEX_EV,221  (_ANY, (_ONE, 'AavP', 'SevP')),222  (_ANY,223   (_ONE,224    (_ONE,225     (_ONE,226      (_ALL, 'TP', 'TP'),227      'TP'228     ),229     'PP'230    ),231    'EVNP'232   )233  ),234  (_ANY,235   'AavP',236   (_ONE,237    (_ALL, _LEX_CONJ, (_ONE, 'VP', 'EVP')),238    'PP'239   )240  ),241 ),242 'EVhP': (_ALL,243  _LEX_EV,244  'TP',245  (_ANY, 'AavP')246 ),247 'EVscP': (_ALL,248  _LEX_EV,249  (_ANY, 'AavP'),250  (_ANY,251   (_ONE,252    'tes$%i' % (_DLCT_CENTRAL),253    'ut$%i' % (_DLCT_CENTRAL),254    'anw$%i' % (_DLCT_METAFALSS),255    'dn$%i' % (_DLCT_PASTALIE),256    'du$%i' % (_DLCT_PASTALIE),257    'tie$%i' % (_DLCT_PASTALIE),258    'tou$%i' % (_DLCT_CENTRAL),259    'ween$%i' % (_DLCT_CENTRAL),260    'won$%i' % (_DLCT_CENTRAL),261    'elle$%i' % (_DLCT_CENTRAL)262   )263  ),264  'NsP',265  (_ANY,266   (_ALL, _LEX_CONJ, (_ONE, 'VP', 'EVP'))267  )268 ),269 'EVsclP': (_ALL,270  'EVscP',271  (_ANY, 'EVsclP')272 ),273 'NP': (_ALL,274  (_ANY, 'AnP'),275  (_ONE,276   (_ALL, _LEX_N, 'NP'),277   _LEX_N,278   'PP'279  ),280  (_ANY,281   (_ALL,282    (_ONE,283     _LEX_CONJ,284     'oz$%i' % (_DLCT_CENTRAL),285     'ween$%i' % (_DLCT_CENTRAL),286     'won$%i' % (_DLCT_CENTRAL),287     'elle$%i' % (_DLCT_CENTRAL)288    ),289    'NP'290   )291  )292 ),293 'NsP': (_ALL,294  (_ANY, 'AnP'),295  (_ONE,296   (_ALL, _LEX_N, 'NsP'),297   _LEX_N298  ),299  (_ANY,300   (_ALL,301    (_ONE,302     _LEX_CONJ,303     'oz$%i' % (_DLCT_CENTRAL),304     'ween$%i' % (_DLCT_CENTRAL),305     'won$%i' % (_DLCT_CENTRAL),306     'elle$%i' % (_DLCT_CENTRAL)307    ),308    'NsP'309   )310  )311 ),312 'NtP': (_ALL,313  (_ANY, 'AnP'),314  _LEX_N,315  (_ANY, 'NtP'),316  (_ANY,317   (_ALL,318    (_ONE,319     _LEX_CONJ,320     'oz$%i' % (_DLCT_CENTRAL),321     'ween$%i' % (_DLCT_CENTRAL),322     'won$%i' % (_DLCT_CENTRAL),323     'elle$%i' % (_DLCT_CENTRAL)324    ),325    'NtP'326   )327  )328 ),329 'PP': (_ALL, (_ONE, _LEX_PREP, _LEX_PRT), 'NP'),330 'SevP': (_ALL,331  (_ONE,332   (_ALL,333    (_ANY,334     (_ALL,335      (_ANY, 'x.$%i' % (_DLCT_PASTALIE)),336      'rre$%i' % (_DLCT_CENTRAL)337     )338    ),339    (_ONE,340     (_ALL, (_ANY, 'AnpP'), _LEX_PRON),341     (_ALL, _LEX_EV, (_ANY, 'AavP'))342    )343   ),344   (_ALL, 'rre$%i' % (_DLCT_CENTRAL), 'NsP')345  )346 ),347 'SevnP': (_ALL,348  'x.$%i' % (_DLCT_PASTALIE),349  'rre$%i' % (_DLCT_CENTRAL),350  'NsP'351 ),352 'SevmP': (_ALL,353  'x.$%i' % (_DLCT_PASTALIE),354  'rre$%i' % (_DLCT_CENTRAL),355  (_ONE,356   (_ALL,357    'EVscP',358    'EVscP',359    (_ANY, 'EVsclP')360   ),361   'EVP',362  )363 ),364 'SgP': (_ALL,365  (_ANY, 'rre$%i' % (_DLCT_CENTRAL)),366  (_ONE,367   (_ALL, (_ANY, 'AnpP'), _LEX_PRON),368   'NsP'369  )370 ),371 'SgsP': (_ALL,372  'rre$%i' % (_DLCT_CENTRAL),373  (_ONE,374   (_ALL, (_ANY, 'AnpP'), _LEX_PRON),375   'NsP'376  )377 ),378 'SpP': (_ALL,379  'x.$%i' % (_DLCT_PASTALIE),380  (_ONE,381   (_ALL, 'rre$%i' % (_DLCT_CENTRAL), 'NsP'),382   (_ALL,383    (_ANY, 'rre$%i' % (_DLCT_CENTRAL)),384    (_ONE,385     'NsP',386     _LEX_PRON,387     (_ALL, _LEX_EV, (_ANY, 'AavP'))388    )389   )390  )391 ),392 'TP': (_ALL,393  (_ANY, (_ONE, _LEX_PRT, _LEX_PREP, 'en$1')),394  'NtP'395 ),396 'VP': (_ALL,397  (_ANY, _LEX_PRON),398  (_ANY, 'AvP'),399  _LEX_V,400  (_ANY, 'AavP'),401  (_ANY,402   (_ONE,403    (_ALL, 'TP', 'TP'),404    'TP'405   ),406   'PP'407  ),408  (_ANY,409   'AaP',410   (_ALL, _LEX_CONJ, (_ONE, 'VP', 'EVP'))411  )412 ),413 'VsP': (_ALL,414  (_ANY, 'AvP'),415  _LEX_V,416  (_ANY, 'AavP'),417  (_ANY, 'NsP'),418  (_ANY,419   (_ALL, _LEX_CONJ, 'VsP')420  )421 ),422} #: Symbolic AST mappings and descriptions.423_PHRASE_REDUCTION = {424 'AaP': 'AP',425 'AavP': 'AP',426 'AnP': 'AP',427 'AnpP': 'AP',428 'AvP': 'AP',429 'CP': 'CP',430 'ESP': 'ESP',431 'EVNP': 'EOP',432 'EVOP': 'EOP',433 'EVP': 'EVP',434 'EVhP': 'EVP',435 'EVscP': 'EVP',436 'NP': 'NP',437 'NsP': 'NP',438 'NtP': 'NP',439 'PP': 'PP',440 'SevP': 'SVP',441 'SevnP': 'SP',442 'SevmP': 'SP',443 'SgP': 'SP',444 'SgsP': 'SP',445 'SpP': 'SP',446 'TP': 'TP',447 'VP': 'VP',448 'VsP': 'VP',449} #: Mappings from phrase-notation to symbolic descriptions.450_PHRASE_EXPANSION = {451 'AP': "Complement Phrase",452 'CP': "Sentence",453 'ESP': "Emotion Sound Phrase",454 'EOP': "Emotion Object Phrase",455 'EVP': "Emotion Verb Phrase",456 'NP': "Noun Phrase",457 'PP': "Preposition Phrase",458 'SP': "Subject Phrase",459 'SVP': "Subject Verb Phrase",460 'TP': "Transitive Phrase",461 'VP': "Verb Phrase",462} #: Mappings from phrase-notation to human-readable descriptions.463_PHRASE_COLOURS = {464 'AP': 3,465 'CP': 0,466 'EOP': 9,467 'ESP': 4,468 'EVP': 5,469 'MP': 7,470 'NP': 1,471 'PP': 6,472 'SP': 8,473 'SVP': 8,474 'TP': 10,475 'VP': 2,476} #: Mappings from symbolic descriptions to colour keys.477_SYNTAX_CLASS = {478 _LEX_ADJ: 'adj.',479 _LEX_ADV: 'adv.',480 _LEX_CNSTR: 'cnstr.',481 _LEX_CONJ: 'conj.',482 _LEX_ESi: 'E.S. (I)',483 _LEX_ESii: 'E.S. (II)',484 _LEX_ESiii: 'E.S. (III)',485 _LEX_EV: 'E.V.',486 _LEX_INTJ: 'intj.',487 _LEX_N: 'n.',488 _LEX_PREP: 'prep.',489 _LEX_PRON: 'pron.',490 _LEX_PRT: 'prt.',491 _LEX_V: 'v.',492} #: Mappings from lexical class constants to human-readable names.493_SYNTAX_CLASS_FULL = {494 _LEX_ADJ: 'adjective',495 _LEX_ADV: 'adverb',496 _LEX_CNSTR: 'language construct',497 _LEX_CONJ: 'conjunction',498 _LEX_ESi: 'Emotion Sound (I)',499 _LEX_ESii: 'Emotion Sound (II)',500 _LEX_ESiii: 'Emotion Sound (III)',501 _LEX_EV: 'Emotion Verb',502 _LEX_INTJ: 'interjection',503 _LEX_N: 'noun',504 _LEX_PREP: 'preposition',505 _LEX_PRON: 'pronoun',506 _LEX_PRT: 'particle',507 _LEX_V: 'verb',508} #: Mappings from lexical class constants to expanded human-readable names.509_SYNTAX_MAPPING = {510 1: (_LEX_EV,),511 2: (_LEX_V,),512 3: (_LEX_ADV,),513 4: (_LEX_N,),514 5: (_LEX_CONJ,),515 6: (_LEX_PREP,),516 7: (_LEX_ESii, _LEX_ADJ), #Doubles as adjective.517 8: (_LEX_ADJ, _LEX_ESii), #Doubles as E.S.(II).518 9: (_LEX_N, _LEX_V),519 10: (_LEX_ADJ, _LEX_N, _LEX_ESii), #Doubles as E.S.(II).520 11: (_LEX_ADJ, _LEX_V, _LEX_ESii), #Doubles as E.S.(II).521 12: (_LEX_PRT,),522 13: (_LEX_ESiii,),523 14: (_LEX_ESi,),524 15: (_LEX_PRON, _LEX_N,),525 16: (_LEX_ADV, _LEX_INTJ),526 17: (_LEX_PREP, _LEX_PRT),527 18: (_LEX_CNSTR,),528 19: (_LEX_ADV, _LEX_N),529 20: (_LEX_ADV, _LEX_ADJ, _LEX_ESii), #Doubles as E.S.(II).530 21: (_LEX_CONJ, _LEX_PREP),531 22: (_LEX_V, _LEX_PRT),532 23: (_LEX_ADV, _LEX_PRT),533 24: (_LEX_N, _LEX_PREP),534 25: (_LEX_ADV, _LEX_PREP),535} #: Mappings from lexical class database values to their constituent lexical class constants.536_DIALECT = {537 _DLCT_UNKNOWN: 'Unknown',538 _DLCT_CENTRAL: 'Central Standard Note',539 _DLCT_CULT_CIEL: 'Cult Ciel Note',540 _DLCT_CLUSTER: 'Cluster Note',541 _DLCT_ALPHA: 'Alpha Note',542 _DLCT_METAFALSS: 'Metafalss Note',543 _DLCT_PASTALIE: 'New Testament of Pastalie',544 _DLCT_ALPHA_EOLIA: 'Alpha Note (EOLIA)',545} #: Mappings from dialect constants to human-readable names.546_COLLIDING_EMOTION_VERBS = (547 'd.n.',548) #: A collection of all Emotion Verbs that collide with basic words in the sanitization process.549class _SyntaxTree(object):550	_children = None551	_phrase = None552	553	def __init__(self):554		self._phrase = "CP"555		self._children = []556		557	def addChild(self, syntax_tree):558		self._children.append(syntax_tree)559		560	def getChildren(self):561		return tuple(self._children)562		563	def toXML(self):564		document = xml.dom.minidom.getDOMImplementation().createDocument(None, "s", None)565		566		self._xml_attachNodes(document, document.firstChild)567		568		return document.toprettyxml()569		570	def _xml_attachNodes(self, document, parent):571		node = document.createElement(self._phrase.lower())572		parent.appendChild(node)573		574		phrase_node = document.createElement("phrase")575		phrase_node.appendChild(document.createTextNode(_PHRASE_EXPANSION[_PHRASE_REDUCTION[self._phrase]]))576		node.appendChild(phrase_node)577		578		for child in self._children:579			child._xml_attachNodes(document, node)580			581	def countLeaves(self):582		return sum([child.countLeaves() for child in self._children])583		584	def getPhrase(self):585		return self._phrase586		587class _Phrase(_SyntaxTree):588	def __init__(self, phrase):589		self._phrase = phrase590		self._children = []591		592class _Word(_SyntaxTree):593	_children = ()594	_word = None595	_meaning = None596	_class = None597	_dialect = None598	_prefix = None599	_suffix = None600	_slots = None601	602	def __init__(self, word, meaning, syntax_class, dialect, prefix, suffix, slots):603		self._word = word604		self._meaning = meaning605		self._class = syntax_class606		self._dialect = dialect607		self._prefix = prefix608		self._suffix = suffix609		self._slots = slots610		611	def getWord(self, xhtml=False):612		return _decorateWord(self._word, self._prefix, self._suffix, self._slots, xhtml)613		614	def getBaseWord(self):615		return self._word616		617	def getMeaning(self, xhtml=False):618		if xhtml:619			return cgi.escape(self._meaning)620		return self._meaning621		622	def getClass(self):623		return self._class624		625	def getDialect(self):626		return self._dialect627		628	def getPhrase(self):629		return None630		631	def _xml_attachNodes(self, document, parent):632		node = document.createElement("word")633		parent.appendChild(node)634		635		node.setAttribute("dialect", str(self._dialect))636		637		hymmnos_node = document.createElement("hymmnos")638		hymmnos_node.appendChild(document.createTextNode(_decorateWord(self._word, self._prefix, self._suffix, self._slots, False)))639		node.appendChild(hymmnos_node)640		641		class_node = document.createElement("class")642		class_node.appendChild(document.createTextNode(_SYNTAX_CLASS[self._class]))643		node.appendChild(class_node)644		645		meaning_node = document.createElement("meaning")646		meaning_node.appendChild(document.createTextNode(self._meaning))647		node.appendChild(meaning_node)648		649		dialect_node = document.createElement("dialect")650		dialect_node.appendChild(document.createTextNode(_DIALECT[self._dialect % _DIALECT_SHIFT]))651		node.appendChild(dialect_node)652		653	def countLeaves(self):654		return 1655		656		657def processSyntax(line, db_con):658	lookup.initialiseEmotionVerbRegexps(db_con)659	660	tree = _SyntaxTree()661	(display_string, result) = _processInput(tree, line.split(), db_con)662	663	return (tree, display_string, result)664	665def renderResult_xhtml(tree, display_string):666	return """667		<table class="result" style="border-collapse: collapse; border: 1px solid black; width: 100%%;">668			<tr>669				<td style="color: #00008B; text-align: center; background: #D3D3D3;">670					<div style="font-family: hymmnos, sans; font-size: 24pt;">%(display_string)s</div>671					<div style="font-size: 18pt;">%(display_string)s</div>672				</td>673			</tr>674			<tr>675				<td style="background: #808080; color: white;">676					<div style="width: 100%%;">677						%(branches)s678					</div>679				</td>680			</tr>681			<tr>682				<td style="color: #00008B; text-align: right; background: #D3D3D3; font-size: 0.7em;">683					You may wish to <a href="./search.php?%(display_string_translate)s">684						translate this sentence word-for-word685					</a> or <a href="./syntax-xml.py?%(display_string_xml)s">686						view it as XML687					</a>688				</td>689			</tr>690		</table>691		<hr/>692		<div style="color: #808080; font-size: 0.6em;">693			<span>694				Lexical classes reflect instance, not abstraction.695				<br/>696				The syntax tree does not take Emotion Vowels into consideration.697			</span>698		</div>699	""" % {700	 'display_string': display_string,701	 'branches': _renderBranches(tree),702	 'display_string_translate': urllib.urlencode({'word': display_string}),703	 'display_string_xml': urllib.urlencode({'query': display_string}),704	}705	706def _decorateWord(word, prefix, suffix, slots, xhtml):707		if not slots is None:708			slots = map(cgi.escape, slots)709		else:710			slots = ()711		prefix = prefix or ''712		suffix = suffix or ''713		714		if xhtml:715			slots = [''.join(('<span style="color: #FFD700;">', slot, '</span>',)) for slot in slots]716			if prefix:717				prefix = ''.join(('<span style="color: #F0D000;">', cgi.escape(prefix), '</span>',))718			if suffix:719				suffix = ''.join(('<span style="color: #FF00FF;">', cgi.escape(suffix), '</span>',))720			word = cgi.escape(word)721			722		word_fragments = word.split('.')723		word = ''724		for (fragment, slot) in zip(word_fragments[:-1], slots):725			word += fragment + slot726		word = prefix + word + word_fragments[-1] + suffix727		728		if not xhtml:729			word = cgi.escape(word)730			731		return word732		733def _digestTokens(tokens, db_con):734	(pastalie, pastalie_prefix_only, words, prefixes, suffixes, slots) = _sanitizePastalie(tokens)735	pastalie_prefix_valid = False #Enforces Pastalie when a Pastalie prefix is present.736	737	word_list = lookup.readWords(words, db_con)738	decorated_words = []739	words_details = []740	for (w, p, s, l) in zip(words, prefixes, suffixes, slots):741		lexicon_entry = word_list.get(w.lower())742		if lexicon_entry is None:743			if w.isdigit(): #It's a number.744				lexicon_entry = ([w, w, w, 8, 1, None, ''],)745			if p: #Reattach the prefix, since it may be a song or a mistakenly capitalized word.746				song_check = p.lower() + w.lower()747				p = None748				lexicon_entry = lookup.readWords((song_check,), db_con).get(song_check)749			if lexicon_entry is None:750				raise ContentError("unknown word in input: %(word)s" % {751				 'word': w,752				})753		elif pastalie and p:754			pastalie_prefix_valid = True755			756			pastalie_entry = 0757			for (i, l_e) in enumerate(lexicon_entry):758				if l_e[4] % _DIALECT_SHIFT == _DLCT_PASTALIE: #Favour Pastalie forms.759					pastalie_entry = i760			#Duplicate the best candidate, mark it as a noun, and use it to replace the list.761			new_entry = lexicon_entry[i][:]762			new_entry[3] = 4763			lexicon_entry = (new_entry,)764		else:765			if not s and w in _COLLIDING_EMOTION_VERBS: #Handle exceptions where Emotion Verbs match basic words.766				basic_form = w.replace('.', '')767				l_e = lookup.readWords((basic_form,), db_con).get(basic_form)768				if l_e: #Just in case this fails somehow.769					lexicon_entry = tuple([l_e[0]] + list(lexicon_entry))770					771		decorated_words.append(_decorateWord(lexicon_entry[0][0], p, s, l, False))772		words_details.append((lexicon_entry, p, s, l))773	return (words_details, ' '.join(decorated_words), pastalie_prefix_valid or (pastalie and not pastalie_prefix_only))774	775def _processAST(words, ast, phrase=None):776	#Refuse to process requests that would invariably lead to failure.777	if words:778		if phrase in ('AnP', 'AvP', 'AnlP', 'AvlP'):779			if len(words) == 1:780				return None781			else:782				relevant_classes = None783				if phrase in ('AnP', 'AnlP'):784					relevant_classes = (_LEX_N,)785				else:786					relevant_classes = (_LEX_EV, _LEX_V)787				filter_classes = (_LEX_ADV, _LEX_ADJ)788				following_classes = [_SYNTAX_MAPPING[c] for (w, m, k, c, d, e, s) in words[1][0]]789				for classes in [_SYNTAX_MAPPING[c] for (w, m, k, c, d, e, s) in words[0][0]]:790					if len(classes) > 1 and [None for c in classes if c in filter_classes] and [None for c in classes if c in relevant_classes]: #Variable, stop-on-able item.791						for f_classes in following_classes:792							if not [None for c in f_classes if c in relevant_classes]: #Not AP-eligible.793								return None794		if phrase in ('AaP', 'AalP'):795			word = words[0][0][0]796			if "%(word)s$%(dialect)i" % {797			 'word': word[0],798			 'dialect': word[4],799			} in (800			 're$%(dialect)i' % {'dialect': _DLCT_CENTRAL,},801			 'na$%(dialect)i' % {'dialect': _DLCT_CENTRAL,},802			 'zz$%(dialect)i' % {'dialect': _DLCT_PASTALIE,},803			): #These are prefixes only.804				return None805				806	#Process AST normally.807	tuple_rule = ast[0]808	working_words = words[:]809	successes = []810	811	success = False812	for st_a in ast[1:]:813		offset = 0814		result = None815		if type(st_a) == int: #Word from specific lexical class needed.816			result = _processWord_int(working_words, st_a)817			if result:818				offset = result.countLeaves()819				successes.append((result,))820		elif type(st_a) == str:821			if _EXACT_MATCH_REGEXP.match(st_a): #Exact word needed.822				result = _processWord_exact(working_words, st_a)823				if result:824					offset = result.countLeaves()825					successes.append((result,))826			else: #Symbolic AST identifier.827				result = _processAST(working_words, _AST_FRAGMENTS[st_a], st_a)828				if result:829					offset = sum([r.countLeaves() for r in result])830					successes.append(result)831		else: #tuple, meaning nested AST.832			result = _processAST(working_words, st_a)833			if result:834				offset = sum([r.countLeaves() for r in result])835				successes.append(result)836		success = not result == None837		838		if not success and tuple_rule == _ALL: #Failed.839			return None840		elif success and tuple_rule == _ONE: #End lookup.841			break842		elif offset: #Consume tokens before next cycle.843			working_words = working_words[offset:]844			845	if not success and tuple_rule == _ONE: #Failed to get a single success.846		return None847		848	#Successfully validated tuple. Aggregate results.849	nodes = []850	for success in successes:851		for node in success:852			nodes.append(node)853			854	if phrase and nodes and phrase in _PHRASE_REDUCTION: #Construct a parent for the nodes.855		root = _Phrase(phrase)856		for node in nodes:857			root.addChild(node)858		return [root]859	return nodes860	861def _processInput(tree, tokens, db_con):862	#Read the definition of every provided word and construct the displayable Hymmnos string.863	(words_details, display_string, pastalie) = _digestTokens(tokens, db_con)864	865	message = result = None866	if not pastalie:867		result = _processAST(words_details, _GENERAL_AST)868	else:869		result = _processAST(words_details, _PASTALIE_AST)870		871	if result:872		for node in result:873			tree.addChild(node)874			875	if not tree.countLeaves() == len(tokens):876		result = None 877		878	return (display_string, result)879	880def _processWord_exact(words, target):881	if not words:882		return None883		884	(details, prefix, suffix, slots) = words[0]885	for (word, meaning, kana, syntax_class, dialect, decorations, syllables) in details:886		if "%(word)s$%(dialect)i" % {887		 'word': word.lower(),888		 'dialect': dialect % _DIALECT_SHIFT,889		} == target:890			return _Word(word, meaning, _SYNTAX_MAPPING[syntax_class][0], dialect, prefix, suffix, slots)891	return None892	893def _processWord_int(words, target):894	if not words:895		return None896		897	(details, prefix, suffix, slots) = words[0]898	for (word, meaning, kana, syntax_class, dialect, decorations, syllables) in details:899		if target in _SYNTAX_MAPPING[syntax_class]:900			return _Word(word, meaning, target, dialect, prefix, suffix, slots)901	return None902	903def _renderBranches(tree):904	children_entries = []905	for child in tree.getChildren():906		if type(child) == _Word: #Leaf.907			children_entries.append(_renderLeaf(child))908		else:909			children_entries.append(_renderBranches(child))910			911	return """912		<div class="phrase phrase-%(colour)i">913			<span class="phrase-title">%(type)s</span>914			<div class="phrase-content">%(content)s</div>915		</div>916	""" % {917	 'colour': _PHRASE_COLOURS[_PHRASE_REDUCTION[tree.getPhrase()]],918	 'type': _PHRASE_EXPANSION[_PHRASE_REDUCTION[tree.getPhrase()]],919	 'content': '\n'.join(children_entries),920	}921	922def _renderLeaf(leaf):923	base_word = leaf.getBaseWord()924	if base_word.isdigit():925		base_word = '1'926		927	return """<span class="phrase-word-dialect">(%(base_dialect)s)</span>928		<div class="phrase-word phrase-word-%(class)i">929			<a href="javascript:popUpWord('%(base_word)s', %(dialect)i)" style="color: white;">930				%(word)s931			</a>932			<span class="phrase-word-class">(%(syntax_class)s)</span>933			<div class="phrase-word-meaning">%(meaning)s</div>934		</div>935	""" % {936	 'base_dialect': _DIALECT[leaf.getDialect() % _DIALECT_SHIFT],937	 'class': leaf.getClass(),938	 'base_word': base_word,939	 'dialect': leaf.getDialect(),940	 'word': leaf.getWord(True),941	 'syntax_class': _SYNTAX_CLASS_FULL[leaf.getClass()],942	 'meaning': leaf.getMeaning(True),943	}944	945def _sanitizePastalie(tokens):946	emotion_verbs = lookup.EMOTION_VERB_REGEXPS947	pastalie = False948	pastalie_prefix_only = True949	950	words = []951	prefixes = []952	suffixes = []953	slots = []954	for token in tokens:955		emotion_hit = False956		for (regexp, emotion_verb, dialect) in emotion_verbs:957			match = regexp.match(token)958			if match:959				words.append(emotion_verb)960				961				prefixes.append(None)962				suffixes.append(match.groups()[-1])963				word_slots = []964				for hit in match.groups()[:-1]:965					if hit is None:966						word_slots.append('.')967					else:968						word_slots.append(hit)969				slots.append(tuple(word_slots))970				971				pastalie = True972				pastalie_prefix_only = False973				emotion_hit = True974				break975		if emotion_hit:976			continue977			978		match = lookup.WORD_STRUCTURE_REGEXP.match(token)979		if match and (match.group(1) or match.group(3)):980			words.append(match.group(2))981			prefixes.append(match.group(1))982			suffixes.append(match.group(3))983			slots.append(None)984			985			pastalie = True986			if match.group(3):987				pastalie_prefix_only = False988			continue989			990		words.append(token)991		prefixes.append(None)992		suffixes.append(None)993		slots.append(None)994		995	return (pastalie, pastalie_prefix_only, words, prefixes, suffixes, slots)996	997	998class Error(Exception):999	"""1000	This class serves as the base from which all exceptions native to this1001	module are derived.1002	"""1003	description = None #: A description of the error.1004	1005	def __str__(self):1006		"""1007		This function returns an ASCII version of the description of this Error.1008		1009		When possible, the Unicode version should be used instead.		1010		1011		@rtype: str1012		@return: The description of this error. 1013		"""1014		return str(self.description)1015		1016	def __unicode__(self):1017		"""1018		This function returns the description of this Error.		1019		1020		@rtype: unicode1021		@return: The description of this error. 1022		"""1023		return self._description1024		1025	def __init__(self, description):1026		"""1027		This function is invoked when creating a new Error object.1028		1029		@type description: basestring1030		@param description: A description of the problem that this object1031		    represents.1032		1033		@return: Nothing.1034		"""1035		self.description = unicode(description)1036		1037class ContentError(Error):1038	"""1039	This class represents problems that might occur because of invalid data.1040	"""1041	def __init__(self, description):1042		"""1043		This function is invoked when creating a new ContentError object.1044		1045		@type description: basestring1046		@param description: A description of the problem that this object1047		    represents.1048		1049		@return: Nothing.1050		"""1051		self.description = unicode(description)...test_ast.py
Source:test_ast.py  
1# Copyright 2020 The KCL Authors. All rights reserved.2import typing3import pathlib4import hashlib5import unittest6import kclvm.kcl.ast as ast7import kclvm.compiler.parser as parser8class TestAst(unittest.TestCase):9    INIT_LINE = 010    INIT_COLUMN = 011    INIT_END_LINE = 012    INIT_END_COLUMN = 013    ast_node = ast.AST(INIT_LINE, INIT_COLUMN, INIT_END_LINE, INIT_END_COLUMN)14    set_methods = [15        "set_line",16        "set_column",17        "set_end_line",18        "set_end_column",19    ]20    get_methods = [21        "get_line",22        "get_column",23        "get_end_line",24        "get_end_column",25    ]26    offset_method = [27        "offset_line",28        "offset_column",29        "offset_end_line",30        "offset_end_column",31    ]32    # line, column, end_line, end_column33    test_params = [0, 10, 22, 23]34    offset_parmas = [-1, 10, 0]35    def test_ast_offset(self):36        for i, method in enumerate(self.offset_method):37            test_method = getattr(self.ast_node, method)38            for offset_value in self.offset_parmas:39                get_method = getattr(self.ast_node, self.get_methods[i])40                before = get_method()41                test_method(offset_value)42                assert get_method() == before + offset_value43    def test_ast_set_get_line_column(self):44        for i, method in enumerate(self.set_methods):45            test_method = getattr(self.ast_node, method)46            test_method(self.test_params[i])47        for i, method in enumerate(self.get_methods):48            test_method = getattr(self.ast_node, method)49            assert test_method() == self.test_params[i]50    def test_set_invalid(self):51        for method in self.set_methods:52            test_method = getattr(self.ast_node, method)53            with self.assertRaises(AssertionError):54                test_method("-1")55            with self.assertRaises(AssertionError):56                self.ast_node.set_line(-1)57    def test_offset_line_invalid(self):58        for method in self.offset_method:59            test_method = getattr(self.ast_node, method)60            with self.assertRaises(AssertionError):61                test_method("-1")62    def test_position_less_than(self):63        _ONE = "one"64        _OTHER = "other"65        _RESULT = "result"66        test_cases = [67            {68                # position invalid69                _ONE: ast.Position(filename="one.k", line=0, column=1),70                _OTHER: ast.Position(filename="one.k", line=0, column=1),71                _RESULT: False,72            },73            {74                # different filename75                _ONE: ast.Position(filename="one.k", line=1, column=1),76                _OTHER: ast.Position(filename="other.k", line=1, column=1),77                _RESULT: False,78            },79            {80                # line number less than81                _ONE: ast.Position(filename="one.k", line=1, column=1),82                _OTHER: ast.Position(filename="one.k", line=2, column=1),83                _RESULT: True,84            },85            {86                # line number larger than87                _ONE: ast.Position(filename="one.k", line=2, column=1),88                _OTHER: ast.Position(filename="one.k", line=1, column=1),89                _RESULT: False,90            },91            {92                # line number equal, column number less than93                _ONE: ast.Position(filename="one.k", line=1, column=0),94                _OTHER: ast.Position(filename="one.k", line=1, column=1),95                _RESULT: True,96            },97        ]98        for t in test_cases:99            expect = t[_RESULT]100            got = t[_ONE].less(t[_OTHER])101            assert (102                expect == got103            ), f"position less than check between {t[_ONE]} and {t[_OTHER]}, expect: {expect}, got: {got}"104    def test_position_valid(self):105        _POS = "pos"106        _RESULT = "result"107        test_cases = [108            {109                # empty filename110                _POS: ast.Position(line=1, column=0),111                _RESULT: False,112            },113            {114                # line number < 1115                _POS: ast.Position(filename="pos.k", line=0, column=0),116                _RESULT: False,117            },118        ]119        for t in test_cases:120            expect = t[_RESULT]121            got = t[_POS].is_valid()122            assert (123                expect == got124            ), f"position valid on {t[_POS]}, expect: {expect}, got: {got}"125    def test_position_less_equal(self):126        _ONE = "one"127        _OTHER = "other"128        _RESULT = "result"129        test_cases = [130            {131                # position invalid132                _ONE: ast.Position(filename="one.k", line=0, column=1),133                _OTHER: ast.Position(filename="one.k", line=0, column=1),134                _RESULT: False,135            },136            {137                # different filename138                _ONE: ast.Position(filename="one.k", line=1, column=1),139                _OTHER: ast.Position(filename="other.k", line=1, column=1),140                _RESULT: False,141            },142            {143                # position less than144                _ONE: ast.Position(filename="one.k", line=1, column=1),145                _OTHER: ast.Position(filename="one.k", line=2, column=1),146                _RESULT: True,147            },148            {149                # position equal150                _ONE: ast.Position(filename="one.k", line=1, column=1),151                _OTHER: ast.Position(filename="one.k", line=1, column=1),152                _RESULT: True,153            },154        ]155        for t in test_cases:156            expect = t[_RESULT]157            got = t[_ONE].less_equal(t[_OTHER])158            assert (159                expect == got160            ), f"position less equal check between {t[_ONE]} and {t[_OTHER]}, expect: {expect}, got: {got}"161    def test_position_equal(self):162        _ONE = "one"163        _OTHER = "other"164        _RESULT = "result"165        test_cases = [166            {167                # position equal168                _ONE: ast.Position(filename="one.k", line=0, column=1),169                _OTHER: ast.Position(filename="one.k", line=0, column=1),170                _RESULT: True,171            },172            {173                # position not equal174                _ONE: ast.Position(filename="one.k", line=0, column=1),175                _OTHER: ast.Position(filename="one.k", line=0, column=2),176                _RESULT: False,177            },178        ]179        for t in test_cases:180            expect = t[_RESULT]181            got = t[_ONE] == (t[_OTHER])182            assert (183                expect == got184            ), f"position equal check between {t[_ONE]} and {t[_OTHER]}, expect: {expect}, got: {got}"185    def test_get_check_sum(self):186        filename = str(pathlib.Path(__file__).parent.joinpath("test_data/check_sum.k"))187        prog = parser.LoadProgram(filename)188        with open(filename, "rb") as f:189            check_sum_expected = hashlib.md5()190            check_sum_expected.update(filename.encode("utf-8"))191            check_sum_expected.update(f.read())192            self.assertEqual(prog.get_check_sum(), check_sum_expected.hexdigest())193    def test_GetArgDefault_invalid(self):194        arg = ast.Arguments()195        self.assertEqual(arg.GetArgDefault(10), None)196    def test_find_nearest_parent_by_type(self):197        prog = parser.LoadProgram("mock.k", k_code_list=["a=1"], set_ast_parent=True)198        target_identifier = prog.pkgs[prog.MAIN_PKGPATH][0].body[0].targets[0]199        self.assertIsNotNone(target_identifier)200        self.assertIsNotNone(target_identifier.parent)201        nearest_schema_expr = target_identifier.find_nearest_parent_by_type(tpe=ast.SchemaExpr)202        self.assertIsNone(nearest_schema_expr)203        204if __name__ == "__main__":...TestLListTP.py
Source:TestLListTP.py  
...4849    def testSearchEmpty(self) -> None:50        self.assertFalse(self._empty.search(1))5152    def test_empty_one(self) -> None:53        self.assertFalse(self._one.isEmpty())54        55    def test_str_one(self) -> None:56        self.assertEqual(str(self._one), "â¬1âââ
")5758    def test_data_one(self) -> None:59        self.assertEqual(self._one._head.data(), 1)6061    def test_next_one(self) -> None:62        self.assertEqual(str(self._one._head.next()), "â
")6364    def test_len_one(self) -> None:65        self.assertEqual(len(self._one), 1)6667    def test_pop_one(self) -> None:68        self.assertEqual(self._one.pop(), 1)69        self.assertTrue(self._one.isEmpty())7071    def test_pop_one_n1(self) -> None:72        self.assertEqual(self._one.pop(-1), 1)73        self.assertTrue(self._one.isEmpty())7475    def test_search_one(self) -> None:76        self.assertTrue(self._one.search(1))77        self.assertFalse(self._one.search(2))7879    def test_empty_two(self) -> None:80        self.assertFalse(self._two.isEmpty())81        82    def test_str_two(self) -> None:83        self.assertEqual(str(self._two), "â¬1âââ¬2âââ
")8485    def test_data_two(self) -> None:86        self.assertEqual(self._two._head.data(), 1)8788    def test_next_two(self) -> None:89        self.assertEqual(str(self._two._head.next()), "â¬2âââ
")9091    def test_len_two(self) -> None:92        self.assertEqual(len(self._two), 2)9394    def test_pop_two_0(self) -> None:95        self.assertEqual(self._two.pop(), 1)96        self.assertEqual(str(self._two), "â¬2âââ
")9798    def test_pop_two_n2(self) -> None:99        self.assertEqual(self._two.pop(-2), 1)100        self.assertEqual(str(self._two), "â¬2âââ
")101102    def test_pop_two_1(self) -> None:103        self.assertEqual(self._two.pop(1), 2)104        self.assertEqual(str(self._two), "â¬1âââ
")105106    def test_pop_two_n1(self) -> None:107        self.assertEqual(self._two.pop(-1), 2)108        self.assertEqual(str(self._two), "â¬1âââ
")109110    def test_search_two(self) -> None:111        self.assertTrue(self._two.search(1))112        self.assertTrue(self._two.search(2))113        self.assertFalse(self._two.search(3))114115    def test_append_empty(self) -> None:116        self._empty.append(3)117        self.assertEqual(len(self._empty), 1)118        self.assertEqual(self._empty._tail.data(), 3)119120    def test_append_one(self) -> None:121        self._one.append(3)122        self.assertEqual(len(self._one), 2)123        self.assertEqual(self._one._tail.data(), 3)124125    def test_append_two(self) -> None:126        self._two.append(3)127        self.assertEqual(len(self._two), 3)128        self.assertEqual(self._two._tail.data(), 3)129130131if __name__ == '__main__':
...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
