예제 #1
0
 def parse_expression_block(self):
     t0 = self._expect_token(OPEN_EXPRESSION_BLOCK)
     e = self.parse_expression()
     t2 = self._expect_token(CLOSE_EXPRESSION_BLOCK)
     return ExpressionStatement(e,
                                span=TextSpan(clone(t0.start_pos),
                                              clone(t2.end_pos)))
예제 #2
0
 def parse_all(self):
     body = list()
     start_pos = clone(self.peek_token().start_pos)
     while True:
         t0 = self.peek_token()
         if t0.type == END_OF_FILE:
             end_pos = clone(t0.end_pos)
             break
         else:
             body.append(self.parse())
     return Template(body, span=TextSpan(start_pos, end_pos))
예제 #3
0
 def parse(self):
     t0 = self.peek_token()
     if t0.type == TEXT:
         self.get_token()
         return TextStatement(self._get_text(t0),
                              span=TextSpan(clone(t0.start_pos),
                                            clone(t0.end_pos)))
     elif t0.type == OPEN_CODE_BLOCK:
         return self.parse_code_block()
     elif t0.type == OPEN_EXPRESSION_BLOCK:
         return self.parse_expression_block()
     elif t0.type == OPEN_STATEMENT_BLOCK:
         return self.parse_statement()
     else:
         self._raise_parse_error(
             t0, [TEXT, OPEN_EXPRESSION_BLOCK, OPEN_STATEMENT_BLOCK])
예제 #4
0
 def scan_string_lit(self):
     value = ''
     start_pos = clone(self._curr_pos)
     escaping = False
     c0 = self.get_char()
     if c0 != '\'':
         raise ScanError(self._filename, clone(self._curr_pos), c0)
     while True:
         ch = self.get_char()
         if ch == '\'':
             break
         elif ch == '\\':
             escaping = True
             continue
         if escaping:
             value += unescape(ch)
         else:
             value += ch
     return Token(STRING_LITERAL, start_pos, clone(self._curr_pos), value)
예제 #5
0
 def scan_raw_identifier(self):
     c0 = self.get_char()
     if not is_id_start(c0):
         raise ScanError(self._filename, clone(self._curr_pos), c0)
     name = c0
     while True:
         ch1 = self.peek_char()
         if is_id_part(ch1):
             self.get_char()
             name += ch1
         else:
             break
     return name
예제 #6
0
 def parse_statement(self):
     t0 = self._expect_token(OPEN_STATEMENT_BLOCK)
     t1 = self.get_token()
     if t1.type == IF_KEYWORD:
         self._statement_stack.append(
             [ENDIF_KEYWORD, ELIF_KEYWORD, ELSE_KEYWORD])
         cond = self.parse_expression()
         self._expect_token(CLOSE_STATEMENT_BLOCK)
         then = list(self.parse_statement_block())
         last_token = self.peek_token()
         cases = [
             IfStatementCase(cond,
                             then,
                             span=TextSpan(clone(t0.start_pos),
                                           clone(last_token.end_pos)))
         ]
         while True:
             first_token = self._expect_token(OPEN_STATEMENT_BLOCK)
             t2 = self.get_token()
             if t2.type == ELIF_KEYWORD:
                 cond = self.parse_expression()
                 self._expect_token(CLOSE_STATEMENT_BLOCK)
                 then = list(self.parse_statement_block())
                 last_token = self.peek_token()
                 cases.append(IfStatementCase(cond, then),
                              span=TextSpan(clone(first_token.start_pos),
                                            clone(last_token.end_pos)))
             elif t2.type == ELSE_KEYWORD:
                 self._expect_token(CLOSE_STATEMENT_BLOCK)
                 self._statement_stack[-1] = [ENDIF_KEYWORD]
                 body = list(self.parse_statement_block())
                 self._expect_token(OPEN_STATEMENT_BLOCK)
                 self._expect_token(ENDIF_KEYWORD)
                 last_token = self._expect_token(CLOSE_STATEMENT_BLOCK)
                 cases.append(
                     IfStatementCase(None,
                                     body,
                                     span=TextSpan(
                                         clone(first_token.start_pos),
                                         clone(last_token.end_pos))))
                 break
             elif t2.type == ENDIF_KEYWORD:
                 last_token = self._expect_token(CLOSE_STATEMENT_BLOCK)
                 break
         return IfStatement(cases,
                            span=TextSpan(clone(t0.start_pos),
                                          clone(last_token.end_pos)))
     elif t1.type == FOR_KEYWORD:
         self._statement_stack.append([ENDFOR_KEYWORD])
         patt = self.parse_pattern()
         self._expect_token(IN_KEYWORD)
         e = self.parse_expression()
         self._expect_token(CLOSE_STATEMENT_BLOCK)
         body = list(self.parse_statement_block())
         self._expect_token(OPEN_STATEMENT_BLOCK)
         self._expect_token(ENDFOR_KEYWORD)
         t7 = self._expect_token(CLOSE_STATEMENT_BLOCK)
         return ForInStatement(patt,
                               e,
                               body,
                               span=TextSpan(clone(t0.start_pos),
                                             clone(t7.end_pos)))
     elif t1.type == JOIN_KEYWORD:
         self._statement_stack.append([ENDJOIN_KEYWORD])
         patt = self.parse_pattern()
         self._expect_token(IN_KEYWORD)
         e = self.parse_expression()
         self._expect_token(WITH_KEYWORD)
         sep = self.parse_expression()
         self._expect_token(CLOSE_STATEMENT_BLOCK)
         body = list(self.parse_statement_block())
         self._expect_token(OPEN_STATEMENT_BLOCK)
         self._expect_token(ENDJOIN_KEYWORD)
         t6 = self._expect_token(CLOSE_STATEMENT_BLOCK)
         return JoinStatement(patt,
                              e,
                              sep,
                              body,
                              span=TextSpan(clone(t0.start_pos),
                                            clone(t6.end_pos)))
     elif t1.type == SETINDENT_KEYWORD:
         self._statement_stack.append([ENDSETINDENT_KEYWORD])
         e = self.parse_expression()
         self._expect_token(CLOSE_STATEMENT_BLOCK)
         body = list(self.parse_statement_block())
         self._expect_token(OPEN_STATEMENT_BLOCK)
         self._expect_token(ENDSETINDENT_KEYWORD)
         t5 = self._expect_token(CLOSE_STATEMENT_BLOCK)
         return SetIndentStatement(e,
                                   body,
                                   span=TextSpan(clone(t0.start_pos),
                                                 clone(t5.end_pos)))
     elif t1.type == NOINDENT_KEYWORD:
         self._statement_stack.append([ENDNOINDENT_KEYWORD])
         self._expect_token(CLOSE_STATEMENT_BLOCK)
         body = list(self.parse_statement_block())
         self._expect_token(OPEN_STATEMENT_BLOCK)
         self._expect_token(ENDNOINDENT_KEYWORD)
         t5 = self._expect_token(CLOSE_STATEMENT_BLOCK)
         return SetIndentStatement(ConstExpression(0),
                                   body,
                                   span=TextSpan(clone(t0.start_pos),
                                                 clone(t5.end_pos)))
     else:
         expected = [
             FOR_KEYWORD, JOIN_KEYWORD, IF_KEYWORD, NOINDENT_KEYWORD,
             SETINDENT_KEYWORD
         ]
         if len(self._statement_stack) > 0:
             expected.extend(self._statement_stack[-1])
         self._raise_parse_error(t1, expected)
예제 #7
0
 def scan(self):
     while True:
         if self._mode == TEXT_MODE:
             yield self.scan_raw_text()
         elif self._mode == CODE_BLOCK_MODE:
             in_string_literal = False
             start_pos = clone(self._curr_pos)
             text = ''
             while True:
                 c0 = self.peek_char(1)
                 c1 = self.peek_char(2)
                 if c0 == '!' and c1 == '}':
                     break
                 if c0 == EOF:
                     raise ScanError(self._filename, start_pos, c0)
                 text += self.get_char()
             self._mode = TEXT_MODE
             end_pos = clone(self._curr_pos)
             yield Token(CODE_BLOCK_CONTENT, start_pos, end_pos, text)
             start_pos = clone(self._curr_pos)
             self.get_char()
             self.get_char()
             end_pos = clone(self._curr_pos)
             yield Token(CLOSE_CODE_BLOCK, start_pos, end_pos)
         elif self._mode == STATEMENT_MODE:
             self.skip_ws()
             start_pos = clone(self._curr_pos)
             c0 = self.peek_char()
             if c0 == EOF:
                 yield Token(END_OF_FILE, clone(self._curr_pos),
                             clone(self._curr_pos))
             elif c0 == ':':
                 self.get_char()
                 yield Token(COLON, start_pos, clone(self._curr_pos))
             elif c0 == '.':
                 self.get_char()
                 yield Token(DOT, start_pos, clone(self._curr_pos))
             elif c0 == '!':
                 self.get_char()
                 c1 = self.get_char()
                 if c1 == '=':
                     yield Token(NEQ_OPERATOR, start_pos,
                                 clone(self._curr_pos), '!=')
                 elif c1 == '}':
                     yield Token(CLOSE_CODE_BLOCK, start_pos,
                                 clone(self._curr_pos))
                 else:
                     raise ScanError(self._filename, clone(self._curr_pos),
                                     c0)
             elif c0 == '%':
                 self.get_char()
                 c1 = self.get_char()
                 if c1 == '}':
                     self._mode = TEXT_MODE
                     yield Token(CLOSE_STATEMENT_BLOCK, start_pos,
                                 clone(self._curr_pos))
                 else:
                     yield Token(MOD_OPERATOR, start_pos,
                                 clone(self._curr_pos), '%')
             elif c0 == '}':
                 self.get_char()
                 c1 = self.get_char()
                 if c1 == '}':
                     self._mode = TEXT_MODE
                     yield Token(CLOSE_EXPRESSION_BLOCK, start_pos,
                                 clone(self._curr_pos))
                 else:
                     raise ScanError(self._filename, clone(self._curr_pos),
                                     c0)
             elif c0 == ',':
                 self.get_char()
                 yield Token(COMMA, start_pos, clone(self._curr_pos))
             elif c0 == '(':
                 self.get_char()
                 yield Token(OPEN_PAREN, start_pos, clone(self._curr_pos))
             elif c0 == ')':
                 self.get_char()
                 yield Token(CLOSE_PAREN, start_pos, clone(self._curr_pos))
             elif c0 == '[':
                 self.get_char()
                 yield Token(OPEN_BRACKET, start_pos, clone(self._curr_pos))
             elif c0 == ']':
                 self.get_char()
                 yield Token(CLOSE_BRACKET, start_pos,
                             clone(self._curr_pos))
             elif c0 == '\'':
                 yield self.scan_string_lit()
             elif is_digit(c0):
                 self.get_char()
                 digits = c0
                 while is_digit(self.peek_char()):
                     digits += self.get_char()
                 yield Token(INTEGER, start_pos, clone(self._curr_pos),
                             int(digits))
             elif is_operator_start(c0):
                 op = c0
                 self.get_char()
                 while is_operator_part(self.peek_char()):
                     op += self.get_char()
                 if not op in OPERATORS:
                     raise ScanError(self._filename, start_pos, op)
                 yield Token(OPERATORS[op], start_pos,
                             clone(self._curr_pos), op)
             elif is_id_start(c0):
                 name = self.scan_raw_identifier()
                 if name in NAMED_OPERATORS:
                     yield Token(NAMED_OPERATORS[name], start_pos,
                                 clone(self._curr_pos), name)
                 elif name in KEYWORDS:
                     yield Token(KEYWORDS[name], start_pos,
                                 clone(self._curr_pos), name)
                 else:
                     yield Token(IDENTIFIER, start_pos,
                                 clone(self._curr_pos), name)
             else:
                 raise ScanError(self._filename, clone(self._curr_pos), c0)
예제 #8
0
 def scan_raw_text(self):
     text = ''
     start_pos = clone(self._curr_pos)
     while True:
         ch0 = self.peek_char(1)
         if ch0 == EOF:
             if len(text) > 0:
                 return Token(TEXT, start_pos, clone(self._curr_pos), text)
             return Token(END_OF_FILE, clone(self._curr_pos),
                          clone(self._curr_pos))
         elif ch0 == '{':
             if len(text) > 0:
                 return Token(TEXT, start_pos, clone(self._curr_pos), text)
             ch1 = self.peek_char(2)
             if ch1 == '{':
                 self._mode = STATEMENT_MODE
                 start_pos = clone(self._curr_pos)
                 self.get_char()
                 self.get_char()
                 return Token(OPEN_EXPRESSION_BLOCK, start_pos,
                              clone(self._curr_pos))
             elif ch1 == '%':
                 self._mode = STATEMENT_MODE
                 start_pos = clone(self._curr_pos)
                 self.get_char()
                 self.get_char()
                 return Token(OPEN_STATEMENT_BLOCK, start_pos,
                              clone(self._curr_pos))
             elif ch1 == '!':
                 self._mode = CODE_BLOCK_MODE
                 start_pos = clone(self._curr_pos)
                 self.get_char()
                 self.get_char()
                 return Token(OPEN_CODE_BLOCK, start_pos,
                              clone(self._curr_pos))
             elif ch1 == '#':
                 start_pos = clone(self._curr_pos)
                 self.get_char()
                 self.get_char()
                 while True:
                     ch2 = self.get_char()
                     if ch2 == '#':
                         ch3 = self.get_char()
                         if ch3 == '}':
                             ch4 = self.peek_char()
                             if ch4 == '\n':
                                 self.get_char()
                             start_pos = clone(self._curr_pos)
                             break
             else:
                 self.get_char()
                 text += ch0
         else:
             self.get_char()
             text += ch0