998 lines · 30.9 KB · C++
RawDownload
////  TextTemplate.cpp//  tools/shaderScribe/src////  Created by Sam Gateau on 12/15/2014.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html#include "TextTemplate.h" #include <stdarg.h>#include <fstream>#include <sstream>#include <algorithm> typedef TextTemplate::Block::Pointer BlockPointer;typedef TextTemplate::Config::Pointer ConfigPointer;typedef TextTemplate::Pointer TextTemplatePointer; const std::string TextTemplate::Tag::NULL_VAR = "_SCRIBE_NULL"; //-----------------------------------------------------------------------------TextTemplate::Config::Config() :    _includes(),    _funcs(),    _logStream(&std::cout),    _numErrors(0),    _includerCallback(TextTemplate::loadFile) {    _paths.push_back("");} const TextTemplatePointer TextTemplate::Config::addInclude(const ConfigPointer& config, const char* include) {    if (!config) {        return TextTemplatePointer();    }     TextTemplatePointer included = config->findInclude(include);    if (included) {        return included;    }     // INcluded doest exist yet so let's try to create it    String includeStream;    if (config->_includerCallback(config, include, includeStream)) {        // ok, then create a new Template on the include file with this as lib        included = std::make_shared<TextTemplate>(include, config);         std::stringstream src(includeStream);         int nbErrors = included->parse(src);        if (nbErrors > 0) {            included->logError(included->_root, "File failed to parse, not included");            return TextTemplatePointer();        }        config->_includes.insert(Includes::value_type(include, included));        return included;    }     return TextTemplatePointer();} const TextTemplatePointer TextTemplate::Config::findInclude(const char* include) {    Includes::iterator includeIt = _includes.find(String(include));    if (includeIt != _includes.end()) {        return (*includeIt).second;    } else {        return TextTemplatePointer();    }} void TextTemplate::Config::addIncludePath(const char* path) {    _paths.push_back(String(path));} bool TextTemplate::loadFile(const ConfigPointer& config, const char* filename, String& source) {    String sourceFile(filename);    String fullfilename;    for (unsigned int i = 0; i < config->_paths.size(); i++) {        fullfilename = config->_paths[i] + sourceFile;        std::ifstream ifs;        ifs.open(fullfilename.c_str());        if (ifs.is_open()) {            std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());            source = str;            ifs.close();            return (source.length() > 0);        }    }     return false;} TextTemplate::Funcs::Funcs() :    _funcs() {} TextTemplate::Funcs::~Funcs() {}  const BlockPointer TextTemplate::Funcs::findFunc(const char* func) {    map::iterator it = _funcs.find(String(func));    if (it != _funcs.end()) {        return (*it).second;    } else {        return BlockPointer();    }} const BlockPointer TextTemplate::Funcs::addFunc(const char* func, const BlockPointer& funcBlock) {    BlockPointer included = findFunc(func);    if (! included) {        _funcs.insert(map::value_type(func, funcBlock));    }    return included;} void TextTemplate::Block::addNewBlock(const Pointer& parent, const Pointer& block) {    if (parent) {        parent->blocks.push_back(block);        block->parent = parent;    }} const BlockPointer& TextTemplate::Block::getCurrentBlock(const Pointer& block) {    if (block && block->command.isBlockEnd()) {        return block->parent;    } else {        return block;    }} void TextTemplate::logError(const Block::Pointer& block, const char* fmt, ...) {    va_list argp;    va_start(argp, fmt);     char buff[256];    sprintf(buff, fmt, argp);     _numErrors++;    log() << block->sourceName << " Error >>" << buff << std::endl;     int level = 1;    displayTree(std::cerr, level); } bool TextTemplate::grabUntilBeginTag(std::istream* str, std::string& grabbed, Tag::Type& tagType) {    std::stringstream dst;    while (!str->eof()) {                std::string datatoken;        getline((*str), datatoken, Tag::BEGIN);        dst << datatoken;                    char next = str->peek();        if (next == Tag::VAR) {            tagType = Tag::VARIABLE;            grabbed = dst.str();            str->get(); // skip tag char            return true;        } else if (next == Tag::COM) {            tagType = Tag::COMMAND;            grabbed = dst.str();            str->get(); // skip tag char            return true;        } else if (next == Tag::REM) {            tagType = Tag::REMARK;            grabbed = dst.str();            str->get(); // skip tag char            return true;        } else {            if (!str->eof()) {                // false positive, just found the Tag::BEGIN without consequence                dst << Tag::BEGIN;                // keep searching            } else {                // end of the file finishing with no tag                tagType = Tag::INVALID;                grabbed = dst.str();                return true;            }        }    }     return false;} bool TextTemplate::grabUntilEndTag(std::istream* str, std::string& grabbed, Tag::Type& tagType) {    std::stringstream dst;     // preEnd char depends on tag type    char preEnd = Tag::COM;    if (tagType == Tag::VARIABLE) {        preEnd = Tag::VAR;    } else if (tagType == Tag::REMARK) {        preEnd = Tag::REM;    }     while (!str->eof() && !str->fail()) {        // looking for the end of the tag means find the next preEnd        std::string dataToken;        getline((*str), dataToken, preEnd);        char end = str->peek();         dst << dataToken;         // and if the next char is Tag::END then that's it        if (end == Tag::END) {            grabbed = dst.str();            str->get(); // eat the Tag::END            return true;        } else {            // false positive, keep on searching            dst << preEnd;        }    }    grabbed = dst.str();    return false;} bool TextTemplate::stepForward(std::istream* str, std::string& grabbed, std::string& tag, Tag::Type& tagType,    Tag::Type& nextTagType) {    if (str->eof()) {        return false;    }                if (!_steppingStarted) {        _steppingStarted = true;        return grabUntilBeginTag(str, grabbed, nextTagType);    }     // Read from the last opening Tag::BEGIN captured to the next Tag::END    if (grabUntilEndTag(str, tag, tagType)) {        // skip trailing space and new lines only after Command or Remark tag block        if ((tagType == Tag::COMMAND) || (tagType == Tag::REMARK)) {            while (!str->eof() && !str->fail()) {                char c = str->peek();                if ((c == ' ') || (c == '\t') || (c == '\n')) {                    str->get();                } else {                    break;                }            }        }         grabUntilBeginTag(str, grabbed, nextTagType);    }     return true; //hasElement;} const BlockPointer TextTemplate::processStep(const BlockPointer& block, std::string& grabbed, std::string& tag,    Tag::Type& tagType) {    switch (tagType) {        case Tag::INVALID:            block->ostr << grabbed;            return block;            break;        case Tag::VARIABLE:            return processStepVar(block, grabbed, tag);            break;        case Tag::COMMAND:            return processStepCommand(block, grabbed, tag);            break;        case Tag::REMARK:            return processStepRemark(block, grabbed, tag);            break;    }     logError(block, "Invalid tag");    return block;} bool TextTemplate::grabFirstToken(String& src, String& token, String& reminder) {    bool goOn = true;    std::string::size_type i = 0;    while (goOn && (i < src.length())) {        char c = src[i];        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == '[') || (c == ']')) {            token += c;        } else {            if (!token.empty()) {                reminder = src.substr(i);                return true;            }        }        i++;    }     return (!token.empty());} bool TextTemplate::convertExpressionToArguments(String& src, std::vector< String >& arguments) {    std::stringstream str(src);    String token;     while (!str.eof()) {        str >> token;        if (!str.fail()) {            arguments.push_back(token);        }    }     return true;} bool TextTemplate::convertExpressionToDefArguments(String& src, std::vector< String >& arguments) {    if (src.empty()) {        return false;    }     std::stringstream argstr(src);    std::stringstream dest;    bool inVar = false;    while (!argstr.eof()) {        // parse the value of a var, try to find a VAR, so look for the pattern BEGIN,VAR ... VAR,END        String token;        char tag;        if (!inVar) {            getline(argstr, token, Tag::BEGIN);            dest << token;            tag = argstr.peek();        } else {            getline(argstr, token, Tag::END);            dest << token;            tag = token.back();        }         if (tag == Tag::VAR) {            if (!inVar) {                // real var coming:                arguments.push_back(dest.str());                inVar = true;            } else {                // real var over                arguments.push_back(dest.str());                inVar = false;            }        } else {            if (argstr.eof()) {                arguments.push_back(dest.str());            } else {                // put back the tag char stolen                dest << (!inVar ? Tag::BEGIN : Tag::END);            }        }    }     return true;} bool TextTemplate::convertExpressionToFuncArguments(String& src, std::vector< String >& arguments) {    if (src.empty()) {        return false;    }    std::stringstream streamSrc(src);    String params;    getline(streamSrc, params, '(');    getline(streamSrc, params, ')');    if (params.empty()) {        return false;    }     std::stringstream str(params);    String token;    int nbTokens = 0;    while (!str.eof()) {        char c = str.peek();        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '.') || (c == Tag::VAR)  || (c == '[') || (c == ']')) {            token += c;        } else if (c == ',') {            if (!token.empty()) {                if (token == Tag::NULL_VAR) {                    arguments.push_back(Tag::NULL_VAR);                } else {                    arguments.push_back(token);                }                nbTokens++;            }            token.clear();        }         str.get();    }     if (token.size()) {        arguments.push_back(token);        nbTokens++;    }     return (nbTokens > 0);} const BlockPointer TextTemplate::processStepVar(const BlockPointer& block, String& grabbed, String& tag) {    // then look at the define    String var = tag;    String varName;    String val;     if (grabFirstToken(var, varName, val)) {        if (!varName.empty()) {            BlockPointer parent = Block::getCurrentBlock(block);             // Add a new BLock             BlockPointer newBlock = std::make_shared<Block>(_root->sourceName);            (newBlock->ostr) << grabbed;             newBlock->command.type = Command::VAR;             newBlock->command.arguments.push_back(varName);             if (!val.empty()) {                convertExpressionToFuncArguments(val, newBlock->command.arguments);            }             Block::addNewBlock(parent, newBlock);             // dive in the new block            return newBlock;        }    }     return block;} const BlockPointer TextTemplate::processStepCommand(const BlockPointer& block, String& grabbed, String& tag) {    // Grab the command name    String command = tag;    String commandName;     if (grabFirstToken(command, commandName, command)) {        if (commandName.compare("def") == 0) {            return processStepDef(block, grabbed, command);        } else if (commandName.compare("if") == 0) {            return processStepCommandIf(block, grabbed, command);        } else if (commandName.compare("endif") == 0) {            return processStepCommandEndIf(block, grabbed, command);        } else if (commandName.compare("else") == 0) {            return processStepCommandElse(block, grabbed, command);        } else if (commandName.compare("elif") == 0) {            return processStepCommandElif(block, grabbed, command);        } else if (commandName.compare("include") == 0) {            return processStepInclude(block, grabbed, command);        } else if (commandName.compare("func") == 0) {            return processStepFunc(block, grabbed, command);        } else if (commandName.compare("endfunc") == 0) {            return processStepEndFunc(block, grabbed, command);        }    }     return block;} const BlockPointer TextTemplate::processStepDef(const BlockPointer& block, String& grabbed, String& def) {    // then look at the define    String varName;    String val;     if (!grabFirstToken(def, varName, val)) {        logError(block, "Invalid Var name in a <def> tag");        return block;    }     BlockPointer parent = Block::getCurrentBlock(block);     // Add a new BLock     BlockPointer newBlock = std::make_shared<Block>(_root->sourceName);    (newBlock->ostr) << grabbed;     newBlock->command.type = Command::DEF;    newBlock->command.arguments.push_back(varName);    if (!val.empty()) {        // loose first character which should be a white space        val = val.substr(val.find_first_not_of(' '));        convertExpressionToDefArguments(val, newBlock->command.arguments);    }     Block::addNewBlock(parent, newBlock);     // dive in the new block    return newBlock;}  const BlockPointer TextTemplate::processStepCommandIf(const BlockPointer& block, String& grabbed, String& expression) {    BlockPointer parent = Block::getCurrentBlock(block);     // Add a new BLock depth    BlockPointer newIfBlock = std::make_shared<Block>(_root->sourceName);    newIfBlock->command.type = Command::IFBLOCK;     Block::addNewBlock(parent, newIfBlock);     BlockPointer newBlock = std::make_shared<Block>(_root->sourceName);    (newBlock->ostr) << grabbed;     newBlock->command.type = Command::IF;    convertExpressionToArguments(expression, newBlock->command.arguments);

Lines 1–500 of 998.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t