1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* 2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2014 Google Inc. 3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be 5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file. 6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrSKSLPrettyPrint.h" 8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkSLString.h" 9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace GrSKSLPrettyPrint { 11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GLSLPrettyPrint { 13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic: 14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot GLSLPrettyPrint() {} 15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSL::String prettify(const char** strings, int* lengths, int count, bool countlines) { 17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fCountlines = countlines; 18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fTabs = 0; 19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fLinecount = 1; 20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fFreshline = true; 21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // If a string breaks while in the middle 'parse until' we need to continue parsing on the 23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // next string 24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fInParseUntilNewline = false; 25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fInParseUntil = false; 26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int parensDepth = 0; 28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // number 1st line 30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->lineNumbering(); 31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (int i = 0; i < count; i++) { 32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // setup pretty state 33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fIndex = 0; 34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fLength = lengths[i]; 35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fInput = strings[i]; 36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (fLength > fIndex) { 38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot /* the heart and soul of our prettification algorithm. The rules should hopefully 39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * be self explanatory. For '#' and '//' tokens we parse until we reach a newline. 40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * For long style comments like this one, we search for the ending token. We also 42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * preserve whitespace in these comments WITH THE CAVEAT that we do the newlines 43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * ourselves. This allows us to remain in control of line numbers, and matching 44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * tabs Existing tabs in the input string are copied over too, but this will look 45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * funny 46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * '{' and '}' are handled in basically the same way. We add a newline if we aren't 48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * on a fresh line, dirty the line, then add a second newline, ie braces are always 49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * on their own lines indented properly. The one funkiness here is structs print 50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * with the semicolon on its own line. Its not a problem for a glsl compiler though 51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * '(' and ')' are basically ignored, except as a sign we need to ignore ';' ala 53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * in for loops. 54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * ';' means add a new line 56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * '\t' and '\n' are ignored in general parsing for backwards compatability with 58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * existing shader code and we also have a special case for handling whitespace 59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * at the beginning of fresh lines. 60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Otherwise just add the new character to the pretty string, indenting if 62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * necessary. 63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fInParseUntilNewline) { 65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->parseUntilNewline(); 66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else if (fInParseUntil) { 67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->parseUntil(fInParseUntilToken); 68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else if (this->hasToken("#") || this->hasToken("//")) { 69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->parseUntilNewline(); 70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else if (this->hasToken("/*")) { 71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->parseUntil("*/"); 72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else if ('{' == fInput[fIndex]) { 73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->newline(); 74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->appendChar('{'); 75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fTabs++; 76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->newline(); 77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else if ('}' == fInput[fIndex]) { 78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fTabs--; 79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->newline(); 80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->appendChar('}'); 81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->newline(); 82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else if (this->hasToken(")")) { 83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot parensDepth--; 84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else if (this->hasToken("(")) { 85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot parensDepth++; 86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else if (!parensDepth && this->hasToken(";")) { 87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->newline(); 88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else if ('\t' == fInput[fIndex] || '\n' == fInput[fIndex] || 89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot (fFreshline && ' ' == fInput[fIndex])) { 90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fIndex++; 91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->appendChar(fInput[fIndex]); 93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fPretty; 97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate: 100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void appendChar(char c) { 101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->tabString(); 102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPretty.appendf("%c", fInput[fIndex++]); 103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fFreshline = false; 104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // hasToken automatically consumes the next token, if it is a match, and then tabs 107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // if necessary, before inserting the token into the pretty string 108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool hasToken(const char* token) { 109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t i = fIndex; 110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (size_t j = 0; token[j] && fLength > i; i++, j++) { 111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (token[j] != fInput[i]) { 112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->tabString(); 116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fIndex = i; 117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPretty.append(token); 118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fFreshline = false; 119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void parseUntilNewline() { 123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (fLength > fIndex) { 124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if ('\n' == fInput[fIndex]) { 125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fIndex++; 126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->newline(); 127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fInParseUntilNewline = false; 128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPretty.appendf("%c", fInput[fIndex++]); 131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fInParseUntilNewline = true; 132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // this code assumes it is not actually searching for a newline. If you need to search for a 136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // newline, then use the function above. If you do search for a newline with this function 137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // it will consume the entire string and the output will certainly not be prettified 138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void parseUntil(const char* token) { 139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (fLength > fIndex) { 140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // For embedded newlines, this code will make sure to embed the newline in the 141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // pretty string, increase the linecount, and tab out the next line to the appropriate 142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // place 143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if ('\n' == fInput[fIndex]) { 144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->newline(); 145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->tabString(); 146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fIndex++; 147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (this->hasToken(token)) { 149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fInParseUntil = false; 150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fFreshline = false; 153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPretty.appendf("%c", fInput[fIndex++]); 154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fInParseUntil = true; 155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fInParseUntilToken = token; 156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // We only tab if on a newline, otherwise consider the line tabbed 160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void tabString() { 161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fFreshline) { 162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (int t = 0; t < fTabs; t++) { 163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPretty.append("\t"); 164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // newline is really a request to add a newline, if we are on a fresh line there is no reason 169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // to add another newline 170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void newline() { 171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!fFreshline) { 172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fFreshline = true; 173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPretty.append("\n"); 174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->lineNumbering(); 175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void lineNumbering() { 179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fCountlines) { 180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fPretty.appendf("%4d\t", fLinecount++); 181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool fCountlines, fFreshline; 185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int fTabs, fLinecount; 186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t fIndex, fLength; 187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const char* fInput; 188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkSL::String fPretty; 189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Some helpers for parseUntil when we go over a string length 191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool fInParseUntilNewline; 192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot bool fInParseUntil; 193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const char* fInParseUntilToken; 194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkSL::String PrettyPrint(const char** strings, int* lengths, int count, bool countlines) { 197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot GLSLPrettyPrint pp; 198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return pp.prettify(strings, lengths, count, countlines); 199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} // namespace GrSKSLPrettyPrint 202