Example #1
0
// Parse one simple selector, e.g.: `type#id.class1.class2.class3`
SimpleSelector CSSParser::parseSimpleSelector(){
    QString tagName;
    QString id;
    QVector<QString> classes;
    if(!eof()){
        QChar c = peekChar();
        if(c == '#'){
            consumeChar('#');
            id = parseIdentifier();
            qDebug() << "#";
        } else if(c == '.') {
            consumeChar('.');
            classes.append(parseIdentifier());
            qDebug() << ".";
        } else if(c == '*'){
            consumeChar('*');//TODO
            qDebug() << "*";
        } else if(isVaidIdentifier(c)){
            //h1 div.note
            tagName = parseIdentifier();
        }
    }
    SimpleSelector ret{tagName, id, classes};
#ifdef CSS_DEBUG
    qDebug() << Q_FUNC_INFO;
#endif /* CSS_DEBUG */
    return ret;

}
static std::vector<AlterMetaDataCommand> parseCommands( const std::string& source)
{
	std::vector<AlterMetaDataCommand> rt;
	std::string::const_iterator si = source.begin(), se = source.end();

	for (si = skipSpaces( si, se); si != se; si = skipSpaces( si, se))
	{
		std::string cmd( parseIdentifier( si, se, _TXT("command name")));
		if (strus::utils::caseInsensitiveEquals( cmd, "Alter"))
		{
			std::string name( parseIdentifier( si, se, _TXT("old element name")));
			std::string newname( parseIdentifier( si, se, _TXT("new element name")));
			std::string type( parseIdentifier( si, se, _TXT("new element type")));

			rt.push_back( AlterMetaDataCommand::AlterElement( name, newname, type));
		}
		else if (strus::utils::caseInsensitiveEquals( cmd, "Add"))
		{
			std::string name( parseIdentifier( si, se, _TXT("element name")));
			std::string type( parseIdentifier( si, se, _TXT("element type name")));

			rt.push_back( AlterMetaDataCommand::AddElement( name, type));
		}
		else if (strus::utils::caseInsensitiveEquals( cmd, "Rename"))
		{
			std::string name( parseIdentifier( si, se, _TXT("old element name")));
			std::string newname( parseIdentifier( si, se, _TXT("new element name")));

			rt.push_back( AlterMetaDataCommand::RenameElement( name, newname));
		}
		else if (strus::utils::caseInsensitiveEquals( cmd, "Delete"))
		{
			std::string name( parseIdentifier( si, se, _TXT("element name")));

			rt.push_back( AlterMetaDataCommand::DeleteElement( name));
		}
		else if (strus::utils::caseInsensitiveEquals( cmd, "Clear"))
		{
			std::string name( parseIdentifier( si, se, _TXT("element name")));
			
			rt.push_back( AlterMetaDataCommand::ClearValue( name));
		}
		si = skipSpaces( si, se);
		if (si == se)
		{
			break;
		}
		else if (*si == ';')
		{
			++si;
		}
		else
		{
			std::string str( si, si+30);
			throw strus::runtime_error( _TXT( "semicolon expected as separator of commands at '..."), str.c_str());
		}
	}
	return rt;
}
Example #3
0
bool
PluginIdentifier::areIdentifiersSimilar(QString id1, QString id2)
{
    QString type1, type2, soName1, soName2, label1, label2;

    parseIdentifier(id1, type1, soName1, label1);
    parseIdentifier(id2, type2, soName2, label2);

    if (type1 != type2 || label1 != label2)
        return false;

    bool similar = (soName1.section('/', -1).section('.', 0, 0) ==
                    soName2.section('/', -1).section('.', 0, 0));

    return similar;
}
Example #4
0
  //----------------------------------------------------------------------------
  bool XmlConfig::setParameter( const std::string& key,
                                const std::string& val,
                                const std::string& type )
  {
    if( !_config )
      return false;

    std::cout << "setParameter(key = " << key
                         << ", val = " << val
                         << ", type = " << type
                         << ")"
                         << std::endl;

    //resolve parts of identifier (Renderer:FeatureX) and find in config
    std::string valname;
    TiXmlNode* container = parseIdentifier(key, valname, true);

    if( key.length() > valname.length() + 1 )
    {
      std::string component_name =
        key.substr(0, key.length() - valname.length() - 1);
      Configurable* comp = findComponent(component_name);
      if( !comp )
        LOG_ERROR("No such component: " << component_name);
      else
        comp->setParameter(valname, val, type);
    }

    //check if exists
    TiXmlNode* node = container->FirstChild(valname);
    TiXmlElement* arg = 0;
    if( node )
    {
      arg = node->ToElement();

      //check if it matches
      int res = checkTypeMatch(key, arg, type);
      if(res == 1)
        arg->SetAttribute("type", type);
      else if(res == 0)
        return false;

    }
    else
    {
      //create new one
      arg = new TiXmlElement( valname );
      container->LinkEndChild(arg);
      arg->SetAttribute("type", type);
    }

    arg->SetAttribute("val", val);

    _dirty_write = true;

    saveFile(); // TODO check if multiple variables changed within small
                //      time window

    return true;
  }
Example #5
0
  //----------------------------------------------------------------------------
  XmlConfig::NodePtr XmlConfig::parseIdentifier( const std::string& identifier,
                                                 size_t pos,
                                                 NodePtr container,
                                                 std::string& valname,
                                                 bool create )
  {
    size_t p = identifier.find_first_of(':', pos);
    if(p == std::string::npos)
    {
      valname = identifier.substr(pos);
      return container;
    }

    assert(container);

    std::string containername = identifier.substr(pos, p-pos);
    TiXmlElement* child = 0;
    TiXmlNode* node = container->FirstChild(containername);
    if( !node )
    {
      if( !create )
        return 0;

      child = new TiXmlElement( containername );
      container->LinkEndChild(child);
    }
    else
      child = node->ToElement();

    return parseIdentifier(identifier, p+1, child, valname, create);
  }
Example #6
0
static void parseSimpleTag (const unsigned char *cp, erlangKind kind)
{
	vString *const identifier = vStringNew ();
	parseIdentifier (cp, identifier);
	makeSimpleTag (identifier, ErlangKinds, kind);
	vStringDelete (identifier);
}
Example #7
0
char *OpenDDLParser::parseName( char *in, char *end, Name **name ) {
    *name = ddl_nullptr;
    if( ddl_nullptr == in || in == end ) {
        return in;
    }

    // ignore blanks
    in = lookForNextToken( in, end );
    if( *in != '$' && *in != '%' ) {
        return in;
    }

    NameType ntype( GlobalName );
    if( *in == '%' ) {
        ntype = LocalName;
    }
    in++;
    Name *currentName( ddl_nullptr );
    Text *id( ddl_nullptr );
    in = parseIdentifier( in, end, &id );
    if( id ) {
        currentName = new Name( ntype, id );
        if( currentName ) {
            *name = currentName;
        }
    }

    return in;
}
Example #8
0
static void parseFunctionTag (const unsigned char *cp, vString *const module)
{
	vString *const identifier = vStringNew ();
	parseIdentifier (cp, identifier);
	makeMemberTag (identifier, K_FUNCTION, module);
	vStringDelete (identifier);
}
Example #9
0
    boost::any visit( FunctionDeclaration functionDeclaration ) {

        extractToken( TokenType::KeywordFunction );

        functionDeclaration->identifier = parseIdentifier();

        extractToken( TokenType::PunctuatorOpeningParenthesis );

        while( !currentTokenIs(TokenType::PunctuatorClosingParenthesis) ) {

            if( !functionDeclaration->arguments.empty() )
                extractToken( TokenType::PunctuatorComma );

            functionDeclaration->arguments.emplace_back(
                parse<_FunctionArgument>() );
        }

        extractToken( TokenType::PunctuatorClosingParenthesis );

        if( !currentTokenIs(TokenType::PunctuatorOpeningBrace) )
            functionDeclaration->returnType = parse<_Type>();

        functionDeclaration->block = parse<_Block>();

        return boost::any();
    }
Example #10
0
    Token Lexer::parseNext() {
        //skip whitespace of the current character
        skipWhitespace();

        //return eof if we are at the end
        if (curChar() == '\0') {
            return Token::Eof;
        }

        Token ret;

        //first check if it is a keyword and return it
        ret = parseKeyword();
        if (ret != Token::None)
            return ret;
        ret = parseSymbol();
        if (ret != Token::None)
            return ret;
        ret = parseIdentifier();
        if (ret != Token::None)
            return ret;
        ret = parseNumeric();
        if (ret != Token::None)
            return ret;

        //if nothing was able to parse it, it must be a character and we return it
        value.character = eatChar();
        return Token::Character;
    }
Example #11
0
/*
 * Directives are of the form:
 * def defp
 * defmacro defmacrop
 * defrecord
 * defmodule
 * defprotocol
 * defimpl
 */
static void parseDirective (const unsigned char *cp, vString *const module)
{
    vString *const directive = vStringNew ();
    const char *const drtv = vStringValue (directive);
    cp = parseIdentifier (cp, directive);
    skipWhitespace (&cp);
    /* if (*cp == '(') */
    /*     ++cp; */

    if (strcmp (drtv, "def") == 0 || strcmp (drtv, "defp") == 0)
        parseSimpleTag (cp, K_FUNCTION);
    else if (strcmp (drtv, "defmacro") == 0 || strcmp (drtv, "defmacrop") == 0)
        parseSimpleTag (cp, K_MACRO);
    else if (strcmp (drtv, "defrecord") == 0)
        parseSimpleTag (cp, K_RECORD);
    else if (strcmp (drtv, "defmodule") == 0)
        parseSimpleTag (cp, K_MODULE);
    else if (strcmp (drtv, "defprotocol") == 0)
        parseSimpleTag(cp, K_PROTOCOL);
    else if (strcmp (drtv, "defimpl") == 0)
        parseSimpleTag(cp, K_IMPL);
    /* Otherwise, it was an import, require, etc. */

    vStringDelete (directive);
}
Example #12
0
/*
 * Directives are of the form:
 * -module(foo)
 * -define(foo, bar)
 * -record(graph, {vtab = notable, cyclic = true}).
 * -type some_type() :: any().
 * -opaque some_opaque_type() :: any().
 */
static void parseDirective (const unsigned char *cp, vString *const module)
{
	/*
	 * A directive will be either a record definition or a directive.
	 * Record definitions are handled separately
	 */
	vString *const directive = vStringNew ();
	const char *const drtv = vStringValue (directive);
	cp = parseIdentifier (cp, directive);
	cp = skipSpace (cp);
	if (*cp == '(')
		++cp;

	if (strcmp (drtv, "record") == 0)
		parseSimpleTag (cp, K_RECORD);
	else if (strcmp (drtv, "define") == 0)
		parseSimpleTag (cp, K_MACRO);
	else if (strcmp (drtv, "type") == 0)
		parseSimpleTag (cp, K_TYPE);
	else if (strcmp (drtv, "opaque") == 0)
		parseSimpleTag (cp, K_TYPE);
	else if (strcmp (drtv, "module") == 0)
		parseModuleTag (cp, module);
	/* Otherwise, it was an import, export, etc. */
	
	vStringDelete (directive);
}
std::vector<MarkupDescription> parseMarkupDescriptions( const std::string& src)
{
	char const* si = src.c_str();
	try
	{
		std::vector<MarkupDescription> rt;
		while (*si)
		{
			si = skipNextNonSpace( si);
			if (!isDigit(*si)) throw std::runtime_error("position number expected as 1st argument of markup description)");
			unsigned int position = parseUintValue( si);
			si = skipNextNonSpace( si);
			unsigned int offset = parseUintValue( si);
			si = skipNextNonSpace( si);
			char type = *si++;
			if (type != '>' && type != '<' && type != '@') throw std::runtime_error("expected '<' or '>' or '@' as type (2nd argument of markup description)");
			si = skipNextNonSpace( si);
			if (!isAlpha(*si)) throw std::runtime_error("identifier expected as 3rd argument of markup description");
			std::string name = parseIdentifier( si);
			si = skipNextNonSpace( si);
			char const* expr = si;
			si = skipEoln( si);
			std::string value( expr, si - expr);
			rt.push_back( MarkupDescription( position, offset, type, name, value));
			++si;
		}
		return rt;
	}
	catch (const std::runtime_error& err)
	{
		std::ostringstream msg;
		msg << "error on line " << getLine( src.c_str(), si) << " of markup description file: " << err.what();
		throw std::runtime_error( msg.str());
	}
}
Example #14
0
QVariant
parseAtom(ParserState &st)
{
    checkEndOfFile(st);

    if (isalpha(*st.ptr))
    {
        return parseIdentifier(st);
    }
    else if (isdigit(*st.ptr))
    {
        return parseNumber(st);
    }
    else if (*st.ptr == '-')
    {
        st.ptr++;
        return -parseNumber(st);
    }
    else if (*st.ptr == '"')
    {
        return parseString(st);
    }
    else
    {
        throw ParserError(QString("unexpected character '%1'").arg(*st.ptr));
    }
}
Example #15
0
PARSENODE_PTR SQLParser::parseExpression() {
    PARSENODE_PTR columnNode = parseIdentifier();
    PARSENODE_PTR opNode = parseOperator();
    PARSENODE_PTR valueNode = parseLiteral();
    opNode->children.push_back(columnNode);
    opNode->children.push_back(valueNode);
    return opNode;
}
Example #16
0
  bool parse(const char *subEngineString) {
    // Ignore whitespaces
    subEngineString = parseWhitespaces(subEngineString);

    // Extract engine identifier. It can be empty at this point
    const char *beginOfIdentifier = subEngineString;
    subEngineString = parseIdentifier(subEngineString);
    engineName.assign(beginOfIdentifier, subEngineString - beginOfIdentifier);

    // Ignore whitespaces
    subEngineString = parseWhitespaces(subEngineString);

    // String termination is allowed at this place
    if (!*subEngineString)
        return true;

    // Otherwise colon must be specified and engine identifier cannot be empty
    if (!engineName.length() ||  (*subEngineString != ':')
            ||  (*(subEngineString+1) == '\0'))
        LOG(FATAL) << "Wrong engine specification";

    // Process sub engines
    subEngineString++;
    while (true) {
      // Ignore separators
      subEngineString = parseSeparators(subEngineString);

      // String termination is allowed at this place
      if (!*subEngineString)
          return true;

      // Extract sub engine identifier
      const char *beginOfIdentifier = subEngineString;
      subEngineString = parseIdentifier(subEngineString);

      // Identifier can not be empty nor contain invalid characters
      if (beginOfIdentifier == subEngineString)
          return false;

      // Collect all valid sub engine names
      std::string subEngineName;
      subEngineName.assign(beginOfIdentifier,
              subEngineString - beginOfIdentifier);
      subEngines.push_back(subEngineName);
    }
  }
Example #17
0
Unit CSSParser::parseUnit(){
    QString u = parseIdentifier().toLower();
    if (u == "px") {
        return Unit::Px;
    } else {
        qDebug() << "Unrecognized unit";
        return Unit::Undefined;
    }
}
Example #18
0
FactorPtr Parser::parseFactor()
{
    FactorPtr factor(new Factor);

    if (m_curToken.tokenType() == TokenType::Number) {
        factor->number = parseNumber();
        if (m_errorCode > ErrorCodes::NoError) {
            panic(factorFollow, factorFollowSize);
            return FactorPtr();
        }

        return factor;
    } else if (m_curToken.tokenType() == TokenType::LParen) {
        match(TokenType::LParen);

        ExpressionPtr expr = parseExpression();
        if (m_errorCode > ErrorCodes::NoError) {
            panic(factorFollow, factorFollowSize);
            return FactorPtr();
        }

        if (!match(TokenType::RParen)) {
            reportError(ErrorCodes::ExpectedRParen);

            panic(factorFollow, factorFollowSize);
            return FactorPtr();
        }

        factor->expression = expr;
        return factor;
    } else if (m_curToken.tokenType() == TokenType::Not) {
        match(TokenType::Not);

        factor->negatedFactor = parseFactor();
        if (m_errorCode > ErrorCodes::NoError) {
            panic(factorFollow, factorFollowSize);
            return FactorPtr();
        }

        return factor;
    }

    IdentifierPtr identifier = parseIdentifier();
    if (m_errorCode > ErrorCodes::NoError) {
        panic(factorFollow, factorFollowSize);
        return FactorPtr();
    }

    parseFactor_p(identifier);
    if (m_errorCode > ErrorCodes::NoError) {
        panic(factorFollow, factorFollowSize);
        return FactorPtr();
    }

    factor->id = identifier;
    return factor;
}
bool CVarConsole::parseInput(char* input) {
	if(strlen(input) == 0) return true;

	if(parseAssignment(input)) return true;
	if(parseCommand(input)) return true;
	if(parseIdentifier(input)) return true;

	return false;
}
Example #20
0
bool parseObject(File& file, Object& out_obj)
{
	file.str++; // consume '{'

	skipWhitespaces(file);

	while(*file.str != '}')
	{
		std::string key;

		uint32_t key_line_num = file.current_line_num;

		if(!parseIdentifier(file, key))
		{
			std::cout << "Line " << key_line_num << ": Error parsing identifier!\n";
			return false;
		}
		else if(key.empty())
		{
			std::cout << "Line " << key_line_num << ": Identifier can't be an empty string!\n";
			return false;
		}

		if(out_obj[key] != nullptr)
		{
			std::cout << "Line " << key_line_num << ": Key '" << key << "' already exists!\n";
			return false;
		}

		skipWhitespaces(file);

		if(*file.str != '=')
		{
			std::cout << "Line " << file.current_line_num << ": Expected '=' not found!\n";
			return false;
		}

		file.str++; //consume '='

		skipWhitespaces(file);

		Value value;

		if(!parseValue(file, value))
			return false;

		out_obj.insert(std::move(key), std::move(value), key_line_num);

		skipWhitespaces(file);
	}

	//consume '}'
	file.str++;

	return true;
}
Example #21
0
static bool parseKeywordOrIdentifier(LexerCarriage* carriage, Token* result)
{
    if (parseIdentifier(carriage, result))
    {
        convertToKeywordIfItIs(result->identifierValue, result);
        return true;
    }
    else 
        return false;
}
Example #22
0
static void parseModuleTag (const unsigned char *cp, vString *const module)
{
	vString *const identifier = vStringNew ();
	parseIdentifier (cp, identifier);
	makeSimpleTag (identifier, ErlangKinds, K_MODULE);

	/* All further entries go in the new module */
	vStringCopy (module, identifier);
	vStringDelete (identifier);
}
std::unique_ptr<AST::Terminal> Parser_Ast::Impl::parseRHS()
{
    std::unique_ptr<AST::Terminal> id = parseIdentifier();
    if (id != nullptr)
    {
        return id;
    }

    return parseNumber();
}
Example #24
0
static void readAndEmitTag (const unsigned char** cp, rubyKind expected_kind)
{
	if (isspace (**cp))
	{
		vString *name = vStringNew ();
		vString *chunk = vStringNew ();
		rubyKind actual_kind;
		unsigned int i = 0;

		/* parse the identifier, allowing scoping like "class Foo::Bar::Baz" */
		while (1)
		{
			actual_kind = parseIdentifier (cp, chunk, expected_kind);
			if (i++ > 0)
				vStringPut (name, '.');
			vStringCat (name, chunk);
			vStringClear (chunk);

			if (actual_kind != K_UNDEFINED && (*cp)[0] == ':' && (*cp)[1] == ':')
				*cp += 2;
			else
				break;
		}
		vStringDelete (chunk);
		vStringTerminate (name);

		if (actual_kind == K_UNDEFINED || vStringLength (name) == 0)
		{
			/*
			* What kind of tags should we create for code like this?
			*
			*    %w(self.clfloor clfloor).each do |name|
			*        module_eval <<-"end;"
			*            def #{name}(x, y=1)
			*                q, r = x.divmod(y)
			*                q = q.to_i
			*                return q, r
			*            end
			*        end;
			*    end
			*
			* Or this?
			*
			*    class << HTTP
			*
			* For now, we don't create any.
			*/
		}
		else
		{
			emitRubyTag (name, actual_kind);
		}
		vStringDelete (name);
	}
}
Example #25
0
File: ruby.c Project: jsvisa/ctags
/*
* Copies the characters forming an identifier from *cp into
* name, leaving *cp pointing to the character after the identifier.
*/
static rubyKind parseIdentifier (
        const unsigned char** cp, vString* name, rubyKind kind)
{
    /* Method names are slightly different to class and variable names.
     * A method name may optionally end with a question mark, exclamation
     * point or equals sign. These are all part of the name.
     * A method name may also contain a period if it's a singleton method.
     */
    const char* also_ok = (kind == K_METHOD) ? "_.?!=" : "_";

    skipWhitespace (cp);

    /* Check for an anonymous (singleton) class such as "class << HTTP". */
    if (kind == K_CLASS && **cp == '<' && *(*cp + 1) == '<')
    {
        return K_UNDEFINED;
    }

    /* Check for operators such as "def []=(key, val)". */
    if (kind == K_METHOD || kind == K_SINGLETON)
    {
        if (parseRubyOperator (name, cp))
        {
            return kind;
        }
    }

    /* Copy the identifier into 'name'. */
    while (**cp != 0 && (isalnum (**cp) || charIsIn (**cp, also_ok)))
    {
        char last_char = **cp;

        vStringPut (name, last_char);
        ++*cp;

        if (kind == K_METHOD)
        {
            /* Recognize singleton methods. */
            if (last_char == '.')
            {
                vStringTerminate (name);
                vStringClear (name);
                return parseIdentifier (cp, name, K_SINGLETON);
            }

            /* Recognize characters which mark the end of a method name. */
            if (charIsIn (last_char, "?!="))
            {
                break;
            }
        }
    }
    return kind;
}
Example #26
0
Symbol parseLabelStatement(CharacterSource* source)
{
    CharacterSource s2 = *source;
    Symbol identifier = parseIdentifier(&s2);
    if (!identifier.valid())
        return Symbol();
    Span span;
    if (!Space::parseCharacter(&s2, ':', &span))
        return Symbol();
    return Symbol(atomLabelStatement, identifier,
        new FunctionDefinitionCache(spanOf(identifier) + span));
}
Example #27
0
Symbol parseParameter(CharacterSource* source)
{
    Symbol typeSpecifier = parseTypeConstructorSpecifier(source);
    if (!typeSpecifier.valid())
        return Symbol();
    Symbol name = parseIdentifier(source);
    if (!name.valid())
        source->location().throwError("Expected identifier");
    return Symbol(atomParameter, typeSpecifier, name,
        new IdentifierCache(spanOf(typeSpecifier) + spanOf(name),
            SymbolLabel()));
}
Example #28
0
/*
<source_name> ::= <number> <identifier>
*/
static int parseSourceName(LargeStaticString &src, LargeStaticString &dest, demangle_t &data)
{
  START("SourceName");
  
  int lval;
  if (parseNumber(src, dest, data, lval) == SUCCESS &&
      lval >= 0 && 
      parseIdentifier(src, dest, data, lval) == SUCCESS)
    END_SUCCESS("SourceName");
  
  END_FAIL("SourceName");
}
Example #29
0
///////////////////////////////////////////////////////////////////////////
//
//  Parsing Interface
//
Token *tokenizer_next( Tokenizer *tokenizer ) {
    wchar_t c, next;
    Token *token = NULL;

    next = ss_peek( tokenizer->ss_ );
    while ( next != WEOF && !token ) {
//  Whitespace
        if ( isWhitespaceStart( tokenizer->ss_, 0 ) ) {
            token = parseWhitespace( tokenizer );
        }
//  Strings
        else if ( isStringStart( tokenizer->ss_, 0 ) ) {
            token = parseString( tokenizer );
        }
//  Comments
        else if ( isCommentStart( tokenizer->ss_, 0 ) ) {
            token = parseComment( tokenizer );
        }
//  URL
        else if ( isUrlStart( tokenizer->ss_, 0 ) ) {
            token = parseUrl( tokenizer );
        }
//  SGML Comments
        else if ( isSGMLCommentStart( tokenizer->ss_, 0 ) ) {
            token = parseSGMLComment( tokenizer );
        }
//  Identifier
        else if ( isIdentifierStart( tokenizer->ss_, 0 ) ) {
            token = parseIdentifier( tokenizer );
        }
//  @keyword
        else if ( isAtkeywordStart( tokenizer->ss_, 0 ) ) {
            token = parseAtkeyword( tokenizer );
        }
//  #keyword
        else if ( isHashkeywordStart( tokenizer->ss_, 0 ) ) {
            token = parseHashkeyword( tokenizer );
        }
//  Number
        else if ( isNumberStart( tokenizer->ss_, 0 ) ) {
            token = parseNumber( tokenizer );
        }
//  Operators & Delims (everything else)
        else {
            token = parseEverythingElse( tokenizer );
        }
    }
    if ( token ) {
        return token;
    } else {
        return NULL;
    }
}
Example #30
0
PARSENODE_PTR SQLParser::parseCreate() {
    if (!startsCreate(nowReading)) {
        syntaxError(nowReading, "expect create!");
        return nullptr;
    }
    //LOG_TRACE(logger, "parse create statement.");

    PARSENODE_PTR createNode = PARSENODE_PTR(new ParseNode(CREATE));
    readToken();

    if (nowReading == TABLE) {
        createNode->children.emplace_back(new ParseNode(TABLE));
        readToken();
        
        createNode->children.push_back(parseIdentifier());
        
        expect(LEFT_BRACE);
        while (startsIdentifier(nowReading)) {
            PARSENODE_PTR id = parseIdentifier();
            //LOG_TRACE(logger, "parse id %s.", ((IdentifierNode*)id.get())->id_.c_str());
            PARSENODE_PTR type = parseType();
            if (nowReading == UNIQUE) {
                readToken();
                id->children.emplace_back(new ParseNode(UNIQUE));
            }
            expect(SLICE);
            id->children.push_back(type);
            createNode->children.push_back(id);
        }

        expect(PRIMARY);
        expect(KEY);
        expect(LEFT_BRACE);
        createNode->children.push_back(parseIdentifier());
        expect(RIGHT_BRACE);

        expect(RIGHT_BRACE);
    }
    else if (nowReading == INDEX) {
        createNode->children.emplace_back(new ParseNode(INDEX));
        readToken();

        PARSENODE_PTR indexNode = parseIdentifier();
        createNode->children.push_back(indexNode);
        expect(ON);
        PARSENODE_PTR tableNode = parseIdentifier();
        createNode->children.push_back(tableNode);
        expect(LEFT_BRACE);
        PARSENODE_PTR columnNode = parseIdentifier();
        createNode->children.push_back(columnNode);
        expect(RIGHT_BRACE);
    }
    else {
        syntaxError(nowReading, "expect table or index!");
        return nullptr;
    }

    expect(TERMINATOR);
    return createNode;
}