def testParagraph(self): tokens = [x for x in TeX().input('1\n 2\n \n 3\n').itertokens()] expected = [ Other('1'), Space(' '), Other('2'), Space(' '), EscapeSequence('par'), Other('3'), Space(' ') ] self.assertEqual(tokens, expected)
def testComment(self): tokens = [x for x in TeX().input('line % comment').itertokens()] expected = [ Letter('l'), Letter('i'), Letter('n'), Letter('e'), Space(' ') ] self.assertEqual(tokens, expected)
def testExercises(self): """ Exercises in the TeX book """ # 8.4 tokens = [x for x in TeX().input(r' $x^2$~ \TeX ^^C').itertokens()] expected = [ MathShift('$'), Letter('x'), Superscript('^'), Other('2'), MathShift('$'), EscapeSequence('active::~'), Space(' '), EscapeSequence('TeX'), Other('\x03') ] self.assertEqual(tokens, expected) # 8.5 tokens = [x for x in TeX().input('Hi!\n\n\n').itertokens()] expected = [ Letter('H'), Letter('i'), Other('!'), Space(' '), EscapeSequence('par') ] self.assertEqual(tokens, expected) # 8.6 tokens = [ x for x in TeX().input(r'^^B^^BM^^A^^B^^C^^M^^@\M ').itertokens() ] expected = [ Other('\x02'), Other('\x02'), Letter('M'), Other('\x01'), Other('\x02'), Other('\x03'), Space(' '), EscapeSequence('M') ] self.assertEqual(tokens, expected)
def testTokens(self): tokens = [x for x in TeX().input(r'{\hskip 36 pt}').itertokens()] expected = [ BeginGroup('{'), EscapeSequence('hskip'), Other('3'), Other('6'), Space(' '), Letter('p'), Letter('t'), EndGroup('}') ] self.assertEqual(tokens, expected)
def testDoubleSuper(self): tokens = [x for x in TeX().input('^^I ^^A ^^@ ^^M').itertokens()] expected = [Other('\x01'), Space(' ')] self.assertEqual(tokens, expected)
def testSymbols(self): tokens = [x for x in TeX().input('\\ { } $ & # ^ _ ~ %').itertokens()] expected = [ EscapeSequence(' '), BeginGroup('{'), Space(' '), EndGroup('}'), Space(' '), MathShift('$'), Space(' '), Alignment('&'), Space(' '), Parameter('#'), Space(' '), Superscript('^'), Space(' '), Subscript('_'), Space(' '), EscapeSequence('active::~'), Space(' ') ] self.assertEqual(tokens, expected) tokens = [ x for x in TeX().input( r'\\ \{ \} \$ \& \# \^ \_ \~ \%').itertokens() ] expected = [ EscapeSequence('\\'), Space(' '), EscapeSequence('{'), Space(' '), EscapeSequence('}'), Space(' '), EscapeSequence('$'), Space(' '), EscapeSequence('&'), Space(' '), EscapeSequence('#'), Space(' '), EscapeSequence('^'), Space(' '), EscapeSequence('_'), Space(' '), EscapeSequence('~'), Space(' '), EscapeSequence('%') ] self.assertEqual(tokens, expected)
def evaluate(self, tex, test: Union[List[Token], TeXFragment]) -> _boolToken: """Reorganise a test expression into postfix and evaluate it.""" stack: List[Union[Token, number]] = [] postfix: List[Union[Token, number]] = [] test_iter = iter(test) for tok in test_iter: # Handle literal integers with tex.readNumber number_tokens: List[Token] = [] while tok.catcode == Token.CC_OTHER and (tok not in ['<', '>', '=']): number_tokens.append(tok) tok = next(test_iter, Space()) if len(number_tokens) > 0: value: int = tex.readInternalType(number_tokens, tex.readNumber) postfix.append(number(value)) # Handle parentheses and booleans if tok.catcode == Token.CC_SPACE or tok is None: pass elif isinstance(tok, _boolToken): postfix.append(tok) elif tok.nodeName == '(': stack.append(tok) elif tok.nodeName == ')': while len(stack) > 0: if not isinstance(stack[-1], number) and stack[-1].nodeName == '(': break postfix.append(stack.pop()) stack.pop() # ( else: # Handle operators and precedence while len(stack) > 0 and self.prec(tok) <= self.prec(stack[-1]): postfix.append(stack.pop()) stack.append(tok) while len(stack) > 0: postfix.append(stack.pop()) # Now evaluate the expression in postfix form while len(postfix) > 0: tok = postfix.pop(0) if isinstance(tok, _boolToken): stack.append(tok) elif isinstance(tok, number): stack.append(tok) elif isinstance(tok, _and) or isinstance(tok, AND): op1 = stack.pop() op2 = stack.pop() if isinstance(op1, _boolToken) and isinstance(op2, _boolToken): stack.append(_true() if op1.state and op2.state else _false()) else: raise ValueError('Missing expected boolean value') elif isinstance(tok, _or) or isinstance(tok, OR): op1 = stack.pop() op2 = stack.pop() if isinstance(op1, _boolToken) and isinstance(op2, _boolToken): stack.append(_true() if op1.state or op2.state else _false()) else: raise ValueError('Missing expected boolean value') elif isinstance(tok, _not) or isinstance(tok, NOT): op1 = stack.pop() if isinstance(op1, _boolToken): stack.append(_false() if op1.state else _true()) else: raise ValueError('Missing expected boolean value') elif tok == '>': op2 = stack.pop() op1 = stack.pop() if isinstance(op1, number) and isinstance(op2, number): stack.append(_true() if op1 > op2 else _false()) else: raise ValueError('Missing expected number') elif tok == '<': op2 = stack.pop() op1 = stack.pop() if isinstance(op1, number) and isinstance(op2, number): stack.append(_true() if op1 < op2 else _false()) else: raise ValueError('Missing expected number') elif tok == '=': op2 = stack.pop() op1 = stack.pop() if isinstance(op1, number) and isinstance(op2, number): stack.append(_true() if op1 == op2 else _false()) else: raise ValueError('Missing expected number') if len(stack) > 0 and isinstance(stack[-1], _boolToken): return stack[-1] else: return _false()