10ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson#!/usr/bin/env python 20ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# 30ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# Copyright 2008, Google Inc. 40ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# All rights reserved. 50ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# 60ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# Redistribution and use in source and binary forms, with or without 70ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# modification, are permitted provided that the following conditions are 80ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# met: 90ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# 100ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# * Redistributions of source code must retain the above copyright 110ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# notice, this list of conditions and the following disclaimer. 120ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# * Redistributions in binary form must reproduce the above 130ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# copyright notice, this list of conditions and the following disclaimer 140ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# in the documentation and/or other materials provided with the 150ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# distribution. 160ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# * Neither the name of Google Inc. nor the names of its 170ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# contributors may be used to endorse or promote products derived from 180ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# this software without specific prior written permission. 190ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# 200ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 210ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 220ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 230ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 240ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 250ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 260ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 270ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 280ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 290ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 300ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 310ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 320ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson"""pump v0.1 - Pretty Useful for Meta Programming. 330ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 340ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonA tool for preprocessor meta programming. Useful for generating 350ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonrepetitive boilerplate code. Especially useful for writing C++ 360ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclasses, functions, macros, and templates that need to work with 370ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonvarious number of arguments. 380ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 390ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonUSAGE: 400ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pump.py SOURCE_FILE 410ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 420ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonEXAMPLES: 430ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pump.py foo.cc.pump 440ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Converts foo.cc.pump to foo.cc. 450ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 460ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonGRAMMAR: 470ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson CODE ::= ATOMIC_CODE* 480ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson ATOMIC_CODE ::= $var ID = EXPRESSION 490ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | $var ID = [[ CODE ]] 500ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | $range ID EXPRESSION..EXPRESSION 510ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | $for ID SEPARATOR [[ CODE ]] 520ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | $($) 530ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | $ID 540ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | $(EXPRESSION) 550ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | $if EXPRESSION [[ CODE ]] ELSE_BRANCH 560ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | [[ CODE ]] 570ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | RAW_CODE 580ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson SEPARATOR ::= RAW_CODE | EMPTY 590ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson ELSE_BRANCH ::= $else [[ CODE ]] 600ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | $elif EXPRESSION [[ CODE ]] ELSE_BRANCH 610ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson | EMPTY 620ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson EXPRESSION has Python syntax. 630ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson""" 640ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 650ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson__author__ = 'wan@google.com (Zhanyong Wan)' 660ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 670ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonimport os 680ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonimport re 690ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonimport sys 700ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 710ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 720ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonTOKEN_TABLE = [ 730ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$var\s+'), '$var'), 740ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$elif\s+'), '$elif'), 750ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$else\s+'), '$else'), 760ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$for\s+'), '$for'), 770ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$if\s+'), '$if'), 780ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$range\s+'), '$range'), 790ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$[_A-Za-z]\w*'), '$id'), 800ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$\(\$\)'), '$($)'), 810ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$\$.*'), '$$'), 820ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\$'), '$'), 830ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\[\[\n?'), '[['), 840ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (re.compile(r'\]\]\n?'), ']]'), 850ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson ] 860ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 870ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 880ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass Cursor: 890ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson """Represents a position (line and column) in a text file.""" 900ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 910ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, line=-1, column=-1): 920ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.line = line 930ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.column = column 940ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 950ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __eq__(self, rhs): 960ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return self.line == rhs.line and self.column == rhs.column 970ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 980ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __ne__(self, rhs): 990ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return not self == rhs 1000ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1010ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __lt__(self, rhs): 1020ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return self.line < rhs.line or ( 1030ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.line == rhs.line and self.column < rhs.column) 1040ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1050ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __le__(self, rhs): 1060ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return self < rhs or self == rhs 1070ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1080ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __gt__(self, rhs): 1090ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return rhs < self 1100ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1110ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __ge__(self, rhs): 1120ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return rhs <= self 1130ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1140ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __str__(self): 1150ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if self == Eof(): 1160ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return 'EOF' 1170ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 1180ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return '%s(%s)' % (self.line + 1, self.column) 1190ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1200ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __add__(self, offset): 1210ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return Cursor(self.line, self.column + offset) 1220ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1230ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __sub__(self, offset): 1240ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return Cursor(self.line, self.column - offset) 1250ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1260ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def Clone(self): 1270ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson """Returns a copy of self.""" 1280ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1290ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return Cursor(self.line, self.column) 1300ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1310ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1320ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson# Special cursor to indicate the end-of-file. 1330ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef Eof(): 1340ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson """Returns the special cursor to denote the end-of-file.""" 1350ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return Cursor(-1, -1) 1360ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1370ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1380ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass Token: 1390ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson """Represents a token in a Pump source file.""" 1400ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1410ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, start=None, end=None, value=None, token_type=None): 1420ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if start is None: 1430ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.start = Eof() 1440ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 1450ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.start = start 1460ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if end is None: 1470ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.end = Eof() 1480ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 1490ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.end = end 1500ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.value = value 1510ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.token_type = token_type 1520ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1530ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __str__(self): 1540ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return 'Token @%s: \'%s\' type=%s' % ( 1550ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.start, self.value, self.token_type) 1560ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1570ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def Clone(self): 1580ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson """Returns a copy of self.""" 1590ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1600ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return Token(self.start.Clone(), self.end.Clone(), self.value, 1610ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.token_type) 1620ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1630ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1640ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef StartsWith(lines, pos, string): 1650ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson """Returns True iff the given position in lines starts with 'string'.""" 1660ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1670ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return lines[pos.line][pos.column:].startswith(string) 1680ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1690ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1700ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef FindFirstInLine(line, token_table): 1710ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson best_match_start = -1 1720ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for (regex, token_type) in token_table: 1730ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson m = regex.search(line) 1740ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if m: 1750ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # We found regex in lines 1760ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if best_match_start < 0 or m.start() < best_match_start: 1770ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson best_match_start = m.start() 1780ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson best_match_length = m.end() - m.start() 1790ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson best_match_token_type = token_type 1800ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1810ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if best_match_start < 0: 1820ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return None 1830ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1840ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return (best_match_start, best_match_length, best_match_token_type) 1850ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1860ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1870ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef FindFirst(lines, token_table, cursor): 1880ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson """Finds the first occurrence of any string in strings in lines.""" 1890ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 1900ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson start = cursor.Clone() 1910ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson cur_line_number = cursor.line 1920ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for line in lines[start.line:]: 1930ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if cur_line_number == start.line: 1940ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson line = line[start.column:] 1950ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson m = FindFirstInLine(line, token_table) 1960ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if m: 1970ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # We found a regex in line. 1980ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (start_column, length, token_type) = m 1990ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if cur_line_number == start.line: 2000ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson start_column += start.column 2010ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson found_start = Cursor(cur_line_number, start_column) 2020ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson found_end = found_start + length 2030ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return MakeToken(lines, found_start, found_end, token_type) 2040ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson cur_line_number += 1 2050ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # We failed to find str in lines 2060ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return None 2070ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2080ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2090ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef SubString(lines, start, end): 2100ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson """Returns a substring in lines.""" 2110ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2120ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if end == Eof(): 2130ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson end = Cursor(len(lines) - 1, len(lines[-1])) 2140ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2150ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if start >= end: 2160ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return '' 2170ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2180ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if start.line == end.line: 2190ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return lines[start.line][start.column:end.column] 2200ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2210ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson result_lines = ([lines[start.line][start.column:]] + 2220ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson lines[start.line + 1:end.line] + 2230ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson [lines[end.line][:end.column]]) 2240ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return ''.join(result_lines) 2250ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2260ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2270ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef MakeToken(lines, start, end, token_type): 2280ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson """Creates a new instance of Token.""" 2290ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2300ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return Token(start, end, SubString(lines, start, end), token_type) 2310ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2320ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2330ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef ParseToken(lines, pos, regex, token_type): 2340ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson line = lines[pos.line][pos.column:] 2350ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson m = regex.search(line) 2360ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if m and not m.start(): 2370ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return MakeToken(lines, pos, pos + m.end(), token_type) 2380ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 2390ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print 'ERROR: %s expected at %s.' % (token_type, pos) 2400ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sys.exit(1) 2410ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2420ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2430ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonID_REGEX = re.compile(r'[_A-Za-z]\w*') 2440ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonEQ_REGEX = re.compile(r'=') 2450ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonREST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)') 2460ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonOPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*') 2470ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonWHITE_SPACE_REGEX = re.compile(r'\s') 2480ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff DavidsonDOT_DOT_REGEX = re.compile(r'\.\.') 2490ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2500ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2510ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef Skip(lines, pos, regex): 2520ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson line = lines[pos.line][pos.column:] 2530ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson m = re.search(regex, line) 2540ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if m and not m.start(): 2550ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return pos + m.end() 2560ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 2570ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return pos 2580ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2590ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2600ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef SkipUntil(lines, pos, regex, token_type): 2610ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson line = lines[pos.line][pos.column:] 2620ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson m = re.search(regex, line) 2630ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if m: 2640ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return pos + m.start() 2650ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 2660ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print ('ERROR: %s expected on line %s after column %s.' % 2670ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (token_type, pos.line + 1, pos.column)) 2680ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sys.exit(1) 2690ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2700ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2710ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef ParseExpTokenInParens(lines, pos): 2720ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def ParseInParens(pos): 2730ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX) 2740ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Skip(lines, pos, r'\(') 2750ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Parse(pos) 2760ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Skip(lines, pos, r'\)') 2770ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return pos 2780ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2790ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def Parse(pos): 2800ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = SkipUntil(lines, pos, r'\(|\)', ')') 2810ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if SubString(lines, pos, pos + 1) == '(': 2820ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Parse(pos + 1) 2830ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Skip(lines, pos, r'\)') 2840ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return Parse(pos) 2850ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 2860ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return pos 2870ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2880ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson start = pos.Clone() 2890ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = ParseInParens(pos) 2900ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return MakeToken(lines, start, pos, 'exp') 2910ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2920ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2930ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef RStripNewLineFromToken(token): 2940ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if token.value.endswith('\n'): 2950ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return Token(token.start, token.end, token.value[:-1], token.token_type) 2960ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 2970ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return token 2980ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 2990ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3000ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef TokenizeLines(lines, pos): 3010ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson while True: 3020ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson found = FindFirst(lines, TOKEN_TABLE, pos) 3030ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if not found: 3040ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield MakeToken(lines, pos, Eof(), 'code') 3050ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return 3060ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3070ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if found.start == pos: 3080ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson prev_token = None 3090ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson prev_token_rstripped = None 3100ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 3110ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson prev_token = MakeToken(lines, pos, found.start, 'code') 3120ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson prev_token_rstripped = RStripNewLineFromToken(prev_token) 3130ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3140ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if found.token_type == '$$': # A meta comment. 3150ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if prev_token_rstripped: 3160ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield prev_token_rstripped 3170ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Cursor(found.end.line + 1, 0) 3180ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif found.token_type == '$var': 3190ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if prev_token_rstripped: 3200ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield prev_token_rstripped 3210ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield found 3220ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson id_token = ParseToken(lines, found.end, ID_REGEX, 'id') 3230ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield id_token 3240ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) 3250ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3260ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson eq_token = ParseToken(lines, pos, EQ_REGEX, '=') 3270ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield eq_token 3280ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Skip(lines, eq_token.end, r'\s*') 3290ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3300ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if SubString(lines, pos, pos + 2) != '[[': 3310ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp') 3320ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield exp_token 3330ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Cursor(exp_token.end.line + 1, 0) 3340ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif found.token_type == '$for': 3350ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if prev_token_rstripped: 3360ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield prev_token_rstripped 3370ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield found 3380ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson id_token = ParseToken(lines, found.end, ID_REGEX, 'id') 3390ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield id_token 3400ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX) 3410ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif found.token_type == '$range': 3420ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if prev_token_rstripped: 3430ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield prev_token_rstripped 3440ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield found 3450ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson id_token = ParseToken(lines, found.end, ID_REGEX, 'id') 3460ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield id_token 3470ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX) 3480ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3490ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..') 3500ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield MakeToken(lines, pos, dots_pos, 'exp') 3510ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield MakeToken(lines, dots_pos, dots_pos + 2, '..') 3520ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = dots_pos + 2 3530ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson new_pos = Cursor(pos.line + 1, 0) 3540ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield MakeToken(lines, pos, new_pos, 'exp') 3550ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = new_pos 3560ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif found.token_type == '$': 3570ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if prev_token: 3580ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield prev_token 3590ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield found 3600ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson exp_token = ParseExpTokenInParens(lines, found.end) 3610ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield exp_token 3620ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = exp_token.end 3630ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif (found.token_type == ']]' or found.token_type == '$if' or 3640ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson found.token_type == '$elif' or found.token_type == '$else'): 3650ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if prev_token_rstripped: 3660ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield prev_token_rstripped 3670ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield found 3680ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = found.end 3690ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 3700ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if prev_token: 3710ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield prev_token 3720ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson yield found 3730ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pos = found.end 3740ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3750ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3760ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef Tokenize(s): 3770ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson lines = s.splitlines(True) 3780ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return TokenizeLines(lines, Cursor(0, 0)) 3790ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3800ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3810ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass CodeNode: 3820ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, atomic_code_list=None): 3830ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.atomic_code = atomic_code_list 3840ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3850ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3860ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass VarNode: 3870ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, identifier=None, atomic_code=None): 3880ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.identifier = identifier 3890ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.atomic_code = atomic_code 3900ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3910ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3920ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass RangeNode: 3930ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, identifier=None, exp1=None, exp2=None): 3940ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.identifier = identifier 3950ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.exp1 = exp1 3960ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.exp2 = exp2 3970ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3980ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 3990ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass ForNode: 4000ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, identifier=None, sep=None, code=None): 4010ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.identifier = identifier 4020ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.sep = sep 4030ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.code = code 4040ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4050ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4060ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass ElseNode: 4070ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, else_branch=None): 4080ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.else_branch = else_branch 4090ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4100ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4110ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass IfNode: 4120ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, exp=None, then_branch=None, else_branch=None): 4130ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.exp = exp 4140ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.then_branch = then_branch 4150ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.else_branch = else_branch 4160ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4170ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4180ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass RawCodeNode: 4190ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, token=None): 4200ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.raw_code = token 4210ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4220ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4230ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass LiteralDollarNode: 4240ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, token): 4250ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.token = token 4260ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4270ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4280ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass ExpNode: 4290ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self, token, python_exp): 4300ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.token = token 4310ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.python_exp = python_exp 4320ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4330ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4340ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef PopFront(a_list): 4350ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson head = a_list[0] 4360ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson a_list[:1] = [] 4370ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return head 4380ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4390ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4400ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef PushFront(a_list, elem): 4410ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson a_list[:0] = [elem] 4420ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4430ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4440ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef PopToken(a_list, token_type=None): 4450ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson token = PopFront(a_list) 4460ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if token_type is not None and token.token_type != token_type: 4470ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print 'ERROR: %s expected at %s' % (token_type, token.start) 4480ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print 'ERROR: %s found instead' % (token,) 4490ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sys.exit(1) 4500ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4510ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return token 4520ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4530ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4540ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef PeekToken(a_list): 4550ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if not a_list: 4560ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return None 4570ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4580ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return a_list[0] 4590ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4600ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4610ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef ParseExpNode(token): 4620ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value) 4630ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return ExpNode(token, python_exp) 4640ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4650ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4660ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef ParseElseNode(tokens): 4670ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def Pop(token_type=None): 4680ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return PopToken(tokens, token_type) 4690ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4700ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson next = PeekToken(tokens) 4710ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if not next: 4720ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return None 4730ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if next.token_type == '$else': 4740ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('$else') 4750ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('[[') 4760ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson code_node = ParseCodeNode(tokens) 4770ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop(']]') 4780ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return code_node 4790ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif next.token_type == '$elif': 4800ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('$elif') 4810ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson exp = Pop('code') 4820ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('[[') 4830ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson code_node = ParseCodeNode(tokens) 4840ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop(']]') 4850ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson inner_else_node = ParseElseNode(tokens) 4860ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)]) 4870ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif not next.value.strip(): 4880ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('code') 4890ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return ParseElseNode(tokens) 4900ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 4910ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return None 4920ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4930ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4940ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef ParseAtomicCodeNode(tokens): 4950ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def Pop(token_type=None): 4960ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return PopToken(tokens, token_type) 4970ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 4980ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson head = PopFront(tokens) 4990ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson t = head.token_type 5000ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if t == 'code': 5010ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return RawCodeNode(head) 5020ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif t == '$var': 5030ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson id_token = Pop('id') 5040ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('=') 5050ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson next = PeekToken(tokens) 5060ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if next.token_type == 'exp': 5070ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson exp_token = Pop() 5080ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return VarNode(id_token, ParseExpNode(exp_token)) 5090ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('[[') 5100ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson code_node = ParseCodeNode(tokens) 5110ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop(']]') 5120ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return VarNode(id_token, code_node) 5130ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif t == '$for': 5140ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson id_token = Pop('id') 5150ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson next_token = PeekToken(tokens) 5160ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if next_token.token_type == 'code': 5170ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sep_token = next_token 5180ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('code') 5190ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 5200ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sep_token = None 5210ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('[[') 5220ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson code_node = ParseCodeNode(tokens) 5230ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop(']]') 5240ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return ForNode(id_token, sep_token, code_node) 5250ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif t == '$if': 5260ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson exp_token = Pop('code') 5270ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('[[') 5280ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson code_node = ParseCodeNode(tokens) 5290ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop(']]') 5300ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else_node = ParseElseNode(tokens) 5310ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return IfNode(ParseExpNode(exp_token), code_node, else_node) 5320ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif t == '$range': 5330ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson id_token = Pop('id') 5340ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson exp1_token = Pop('exp') 5350ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop('..') 5360ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson exp2_token = Pop('exp') 5370ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return RangeNode(id_token, ParseExpNode(exp1_token), 5380ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson ParseExpNode(exp2_token)) 5390ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif t == '$id': 5400ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id')) 5410ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif t == '$($)': 5420ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return LiteralDollarNode(head) 5430ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif t == '$': 5440ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson exp_token = Pop('exp') 5450ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return ParseExpNode(exp_token) 5460ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif t == '[[': 5470ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson code_node = ParseCodeNode(tokens) 5480ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson Pop(']]') 5490ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return code_node 5500ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 5510ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson PushFront(tokens, head) 5520ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return None 5530ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 5540ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 5550ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef ParseCodeNode(tokens): 5560ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson atomic_code_list = [] 5570ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson while True: 5580ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if not tokens: 5590ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson break 5600ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson atomic_code_node = ParseAtomicCodeNode(tokens) 5610ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if atomic_code_node: 5620ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson atomic_code_list.append(atomic_code_node) 5630ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 5640ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson break 5650ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return CodeNode(atomic_code_list) 5660ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 5670ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 5680ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef Convert(file_path): 5690ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson s = file(file_path, 'r').read() 5700ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson tokens = [] 5710ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for token in Tokenize(s): 5720ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson tokens.append(token) 5730ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson code_node = ParseCodeNode(tokens) 5740ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return code_node 5750ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 5760ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 5770ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass Env: 5780ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self): 5790ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.variables = [] 5800ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.ranges = [] 5810ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 5820ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def Clone(self): 5830ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson clone = Env() 5840ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson clone.variables = self.variables[:] 5850ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson clone.ranges = self.ranges[:] 5860ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return clone 5870ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 5880ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def PushVariable(self, var, value): 5890ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # If value looks like an int, store it as an int. 5900ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson try: 5910ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson int_value = int(value) 5920ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if ('%s' % int_value) == value: 5930ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson value = int_value 5940ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson except Exception: 5950ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson pass 5960ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.variables[:0] = [(var, value)] 5970ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 5980ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def PopVariable(self): 5990ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.variables[:1] = [] 6000ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6010ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def PushRange(self, var, lower, upper): 6020ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.ranges[:0] = [(var, lower, upper)] 6030ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6040ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def PopRange(self): 6050ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.ranges[:1] = [] 6060ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6070ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def GetValue(self, identifier): 6080ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for (var, value) in self.variables: 6090ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if identifier == var: 6100ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return value 6110ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6120ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print 'ERROR: meta variable %s is undefined.' % (identifier,) 6130ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sys.exit(1) 6140ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6150ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def EvalExp(self, exp): 6160ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson try: 6170ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson result = eval(exp.python_exp) 6180ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson except Exception, e: 6190ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e) 6200ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print ('ERROR: failed to evaluate meta expression %s at %s' % 6210ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (exp.python_exp, exp.token.start)) 6220ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sys.exit(1) 6230ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return result 6240ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6250ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def GetRange(self, identifier): 6260ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for (var, lower, upper) in self.ranges: 6270ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if identifier == var: 6280ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return (lower, upper) 6290ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6300ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print 'ERROR: range %s is undefined.' % (identifier,) 6310ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sys.exit(1) 6320ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6330ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6340ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonclass Output: 6350ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def __init__(self): 6360ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.string = '' 6370ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6380ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def GetLastLine(self): 6390ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson index = self.string.rfind('\n') 6400ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if index < 0: 6410ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return '' 6420ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6430ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return self.string[index + 1:] 6440ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6450ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson def Append(self, s): 6460ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson self.string += s 6470ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6480ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6490ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef RunAtomicCode(env, node, output): 6500ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if isinstance(node, VarNode): 6510ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson identifier = node.identifier.value.strip() 6520ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson result = Output() 6530ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson RunAtomicCode(env.Clone(), node.atomic_code, result) 6540ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson value = result.string 6550ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson env.PushVariable(identifier, value) 6560ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif isinstance(node, RangeNode): 6570ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson identifier = node.identifier.value.strip() 6580ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson lower = int(env.EvalExp(node.exp1)) 6590ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson upper = int(env.EvalExp(node.exp2)) 6600ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson env.PushRange(identifier, lower, upper) 6610ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif isinstance(node, ForNode): 6620ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson identifier = node.identifier.value.strip() 6630ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if node.sep is None: 6640ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sep = '' 6650ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 6660ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sep = node.sep.value 6670ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (lower, upper) = env.GetRange(identifier) 6680ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for i in range(lower, upper + 1): 6690ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson new_env = env.Clone() 6700ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson new_env.PushVariable(identifier, i) 6710ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson RunCode(new_env, node.code, output) 6720ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if i != upper: 6730ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.Append(sep) 6740ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif isinstance(node, RawCodeNode): 6750ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.Append(node.raw_code.value) 6760ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif isinstance(node, IfNode): 6770ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson cond = env.EvalExp(node.exp) 6780ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if cond: 6790ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson RunCode(env.Clone(), node.then_branch, output) 6800ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif node.else_branch is not None: 6810ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson RunCode(env.Clone(), node.else_branch, output) 6820ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif isinstance(node, ExpNode): 6830ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson value = env.EvalExp(node) 6840ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.Append('%s' % (value,)) 6850ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif isinstance(node, LiteralDollarNode): 6860ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.Append('$') 6870ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif isinstance(node, CodeNode): 6880ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson RunCode(env.Clone(), node, output) 6890ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 6900ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print 'BAD' 6910ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print node 6920ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sys.exit(1) 6930ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6940ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6950ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef RunCode(env, code_node, output): 6960ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for atomic_code in code_node.atomic_code: 6970ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson RunAtomicCode(env, atomic_code, output) 6980ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 6990ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7000ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef IsComment(cur_line): 7010ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return '//' in cur_line 7020ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7030ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7040ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef IsInPreprocessorDirevative(prev_lines, cur_line): 7050ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if cur_line.lstrip().startswith('#'): 7060ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return True 7070ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return prev_lines != [] and prev_lines[-1].endswith('\\') 7080ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7090ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7100ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef WrapComment(line, output): 7110ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson loc = line.find('//') 7120ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson before_comment = line[:loc].rstrip() 7130ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if before_comment == '': 7140ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson indent = loc 7150ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 7160ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.append(before_comment) 7170ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson indent = len(before_comment) - len(before_comment.lstrip()) 7180ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson prefix = indent*' ' + '// ' 7190ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson max_len = 80 - len(prefix) 7200ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson comment = line[loc + 2:].strip() 7210ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != ''] 7220ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson cur_line = '' 7230ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for seg in segs: 7240ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if len((cur_line + seg).rstrip()) < max_len: 7250ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson cur_line += seg 7260ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 7270ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if cur_line.strip() != '': 7280ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.append(prefix + cur_line.rstrip()) 7290ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson cur_line = seg.lstrip() 7300ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if cur_line.strip() != '': 7310ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.append(prefix + cur_line.strip()) 7320ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7330ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7340ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef WrapCode(line, line_concat, output): 7350ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson indent = len(line) - len(line.lstrip()) 7360ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson prefix = indent*' ' # Prefix of the current line 7370ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson max_len = 80 - indent - len(line_concat) # Maximum length of the current line 7380ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson new_prefix = prefix + 4*' ' # Prefix of a continuation line 7390ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson new_max_len = max_len - 4 # Maximum length of a continuation line 7400ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # Prefers to wrap a line after a ',' or ';'. 7410ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != ''] 7420ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson cur_line = '' # The current line without leading spaces. 7430ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for seg in segs: 7440ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # If the line is still too long, wrap at a space. 7450ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson while cur_line == '' and len(seg.strip()) > max_len: 7460ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson seg = seg.lstrip() 7470ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson split_at = seg.rfind(' ', 0, max_len) 7480ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.append(prefix + seg[:split_at].strip() + line_concat) 7490ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson seg = seg[split_at + 1:] 7500ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson prefix = new_prefix 7510ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson max_len = new_max_len 7520ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7530ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if len((cur_line + seg).rstrip()) < max_len: 7540ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson cur_line = (cur_line + seg).lstrip() 7550ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 7560ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.append(prefix + cur_line.rstrip() + line_concat) 7570ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson prefix = new_prefix 7580ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson max_len = new_max_len 7590ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson cur_line = seg.lstrip() 7600ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if cur_line.strip() != '': 7610ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.append(prefix + cur_line.strip()) 7620ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7630ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7640ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef WrapPreprocessorDirevative(line, output): 7650ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson WrapCode(line, ' \\', output) 7660ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7670ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7680ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef WrapPlainCode(line, output): 7690ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson WrapCode(line, '', output) 7700ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7710ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7720ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef IsHeaderGuardOrInclude(line): 7730ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or 7740ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson re.match(r'^#include\s', line)) 7750ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7760ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7770ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef WrapLongLine(line, output): 7780ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson line = line.rstrip() 7790ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if len(line) <= 80: 7800ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.append(line) 7810ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif IsComment(line): 7820ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if IsHeaderGuardOrInclude(line): 7830ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # The style guide made an exception to allow long header guard lines 7840ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # and includes. 7850ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.append(line) 7860ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 7870ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson WrapComment(line, output) 7880ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson elif IsInPreprocessorDirevative(output, line): 7890ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if IsHeaderGuardOrInclude(line): 7900ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # The style guide made an exception to allow long header guard lines 7910ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson # and includes. 7920ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output.append(line) 7930ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 7940ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson WrapPreprocessorDirevative(line, output) 7950ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 7960ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson WrapPlainCode(line, output) 7970ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7980ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 7990ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef BeautifyCode(string): 8000ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson lines = string.splitlines() 8010ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output = [] 8020ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson for line in lines: 8030ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson WrapLongLine(line, output) 8040ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output2 = [line.rstrip() for line in output] 8050ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson return '\n'.join(output2) + '\n' 8060ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 8070ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 8080ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsondef main(argv): 8090ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if len(argv) == 1: 8100ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print __doc__ 8110ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson sys.exit(1) 8120ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 8130ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson file_path = argv[-1] 8140ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson ast = Convert(file_path) 8150ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output = Output() 8160ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson RunCode(Env(), ast, output) 8170ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output_str = BeautifyCode(output.string) 8180ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if file_path.endswith('.pump'): 8190ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output_file_path = file_path[:-5] 8200ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 8210ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output_file_path = '-' 8220ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson if output_file_path == '-': 8230ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson print output_str, 8240ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson else: 8250ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output_file = file(output_file_path, 'w') 8260ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output_file.write('// This file was GENERATED by command:\n') 8270ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output_file.write('// %s %s\n' % 8280ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson (os.path.basename(__file__), os.path.basename(file_path))) 8290ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output_file.write('// DO NOT EDIT BY HAND!!!\n\n') 8300ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output_file.write(output_str) 8310ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson output_file.close() 8320ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 8330ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson 8340ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidsonif __name__ == '__main__': 8350ddac1f3791efefb2cffdb425f0c600feb7a47e6Jeff Davidson main(sys.argv) 836