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!!