1
0
Fork 0
forked from len0rd/rockbox

Theme Editor: Got code generation tentatively working along with a solid C++ tree structure for WPS parse trees

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26367 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Robert Bieber 2010-05-29 00:04:04 +00:00
parent 1dcc21d846
commit 6980c1e998
7 changed files with 257 additions and 103 deletions

View file

@ -27,6 +27,7 @@ extern "C"
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <QtGui/QApplication>
#include <QTreeView>
@ -36,15 +37,21 @@ extern "C"
int main(int argc, char* argv[])
{
char doc[] = "%Vd(U);Hey\n%?bl(test,3,5,2,1)<param2|param3>";
char doc[] = "#Comment\n%Vd(U);Hey\n%?bl(test,3,5,2,1)<param2|param3>";
struct skin_element* test = skin_parse(doc);
skin_debug_tree(test);
ParseTreeNode tree(test);
std::cout << "----" << std::endl;
if(std::string(doc) == tree.genCode().toStdString())
std::cout << "Code in/out matches" << std::endl;
else
std::cout << "Match error" << std::endl;
skin_free_tree(test);
/*
QApplication app(argc, argv);
QTreeView tree;
@ -53,7 +60,7 @@ int main(int argc, char* argv[])
tree.show();
return app.exec();
*/
return 0;
}

View file

@ -26,8 +26,8 @@
ParseTreeModel::ParseTreeModel(char* wps, QObject* parent):
QAbstractItemModel(parent)
{
this->wps = skin_parse(wps);
this->root = new ParseTreeNode(this->wps, 0, true);
this->tree = skin_parse(wps);
this->root = new ParseTreeNode(tree, 0);
}
@ -36,6 +36,12 @@ ParseTreeModel::~ParseTreeModel()
delete root;
}
QString genCode()
{
return QString();
}
/*
QModelIndex ParseTreeModel::index(int row, int column,
const QModelIndex& parent) const
{
@ -98,3 +104,4 @@ QVariant ParseTreeModel::data(const QModelIndex &index, int role) const
ParseTreeNode* item = static_cast<ParseTreeNode*>(index.internalPointer());
return item->data(index.column());
}
*/

View file

@ -43,15 +43,19 @@ public:
ParseTreeModel(char* wps, QObject* parent = 0);
virtual ~ParseTreeModel();
QString genCode();
/*
QModelIndex index(int row, int column, const QModelIndex& parent) const;
QModelIndex parent(const QModelIndex &child) const;
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
*/
private:
ParseTreeNode* root;
struct skin_element* wps;
struct skin_element* tree;
};

View file

@ -1,74 +1,200 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Robert Bieber
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
extern "C"
{
#include "symbols.h"
}
#include "parsetreenode.h"
ParseTreeNode::ParseTreeNode(struct skin_element* data, ParseTreeNode* parent,
bool tree)
/* Root element constructor */
ParseTreeNode::ParseTreeNode(struct skin_element* data)
: parent(0), element(0), param(0), children()
{
if(tree)
while(data)
{
while(data)
children.append(new ParseTreeNode(data, this));
data = data->next;
}
}
/* Normal element constructor */
ParseTreeNode::ParseTreeNode(struct skin_element* data, ParseTreeNode* parent)
: parent(parent), element(data), param(0), children()
{
switch(element->type)
{
case TAG:
for(int i = 0; i < element->params_count; i++)
{
appendChild(new ParseTreeNode(data, this, false));
data = data->next;
if(element->params[i].type == skin_tag_parameter::CODE)
children.append(new ParseTreeNode(element->params[i].data.code,
this));
else
children.append(new ParseTreeNode(&element->params[i], this));
}
break;
/* CONDITIONAL and SUBLINES fall through to the same code */
case CONDITIONAL:
case SUBLINES:
for(int i = 0; i < element->children_count; i++)
{
children.append(new ParseTreeNode(data->children[i], this));
}
break;
case LINE:
for(struct skin_element* current = data->children[0]; current;
current = current->next)
{
children.append(new ParseTreeNode(current, this));
}
break;
default:
break;
}
}
/* Parameter constructor */
ParseTreeNode::ParseTreeNode(skin_tag_parameter *data, ParseTreeNode *parent)
: parent(parent), element(0), param(data), children()
{
}
QString ParseTreeNode::genCode() const
{
QString buffer = "";
if(element)
{
switch(element->type)
{
case LINE:
for(int i = 0; i < children.count(); i++)
{
/*
Adding a % in case of tag, because the tag rendering code
doesn't insert its own
*/
if(children[i]->element->type == TAG)
buffer.append(TAGSYM);
buffer.append(children[i]->genCode());
}
break;
case SUBLINES:
for(int i = 0; i < children.count(); i++)
{
buffer.append(children[i]->genCode());
if(i != children.count() - 1)
buffer.append(MULTILINESYM);
}
break;
case CONDITIONAL:
/* Inserts a %?, the tag renderer doesn't deal with the TAGSYM */
buffer.append(TAGSYM);
buffer.append(CONDITIONSYM);
buffer.append(children[0]->genCode());
/* Inserting the sublines */
buffer.append(ENUMLISTOPENSYM);
for(int i = 1; i < children.count(); i++)
{
buffer.append(children[i]->genCode());
if(i != children.count() - 1)
buffer.append(ENUMLISTSEPERATESYM);
}
buffer.append(ENUMLISTCLOSESYM);
break;
case TAG:
/* When generating code, we DO NOT insert the leading TAGSYM, leave
* the calling functions to handle that
*/
buffer.append(element->name);
if(element->params_count > 0)
{
/* Rendering parameters if there are any */
buffer.append(ARGLISTOPENSYM);
for(int i = 0; i < children.count(); i++)
{
buffer.append(children[i]->genCode());
if(i != children.count() - 1)
buffer.append(ARGLISTSEPERATESYM);
}
buffer.append(ARGLISTCLOSESYM);
}
break;
case NEWLINE:
buffer.append('\n');
break;
case TEXT:
buffer.append(element->text);
break;
case COMMENT:
buffer.append(COMMENTSYM);
buffer.append(element->text);
break;
}
}
else if(param)
{
switch(param->type)
{
case skin_tag_parameter::STRING:
buffer.append(param->data.text);
break;
case skin_tag_parameter::NUMERIC:
buffer.append(QString::number(param->data.numeric, 10));
break;
case skin_tag_parameter::DEFAULT:
buffer.append(DEFAULTSYM);
break;
}
parentLink = 0;
}
else
{
element = data;
parentLink = parent;
for(int i = 0; i < children.count(); i++)
buffer.append(children[i]->genCode());
}
return buffer;
}
ParseTreeNode::ParseTreeNode(struct skin_tag_parameter* param,
ParseTreeNode* parent)
:parentLink(parent), element(0), param(param)
{
}
ParseTreeNode::~ParseTreeNode()
{
qDeleteAll(children);
}
void ParseTreeNode::appendChild(ParseTreeNode* child)
{
children.append(child);
}
ParseTreeNode* ParseTreeNode::child(int row)
{
return children[row];
}
int ParseTreeNode::childCount() const
{
return children.count();
}
int ParseTreeNode::columnCount() const
{
return 2;
}
QVariant ParseTreeNode::data(int column) const
{
if(column == 0)
return element->type;
else
return element->line;
}
int ParseTreeNode::row() const
{
if(parentLink)
return parentLink->children.indexOf(const_cast<ParseTreeNode*>(this));
return 0;
}
ParseTreeNode* ParseTreeNode::parent()
{
return parentLink;
}
/*
ParseTreeNode* child(int row);
int numChildren() const;
QVariant data(int column) const;
int getRow() const;
ParseTreeNode* getParent();
*/

View file

@ -1,3 +1,24 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Robert Bieber
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef PARSETREENODE_H
#define PARSETREENODE_H
@ -13,24 +34,23 @@ extern "C"
class ParseTreeNode
{
public:
ParseTreeNode(struct skin_element* data, ParseTreeNode* parent, bool tree);
ParseTreeNode(struct skin_tag_parameter* param, ParseTreeNode* parent);
virtual ~ParseTreeNode();
ParseTreeNode(struct skin_element* data);
ParseTreeNode(struct skin_element* data, ParseTreeNode* parent);
ParseTreeNode(struct skin_tag_parameter* data, ParseTreeNode* parent);
void appendChild(ParseTreeNode* child);
QString genCode() const;
ParseTreeNode* child(int row);
int childCount() const;
int columnCount() const;
int numChildren() const;
QVariant data(int column) const;
int row() const;
ParseTreeNode* parent();
int getRow() const;
ParseTreeNode* getParent();
private:
ParseTreeNode* parentLink;
QList<ParseTreeNode*> children;
ParseTreeNode* parent;
struct skin_element* element;
struct skin_tag_parameter* param;
QList<ParseTreeNode*> children;
};

View file

@ -103,7 +103,14 @@ struct skin_element* skin_parse(char* document)
else
to_write = &(last->next);
if(sublines)
if(*cursor == '\n')
{
*to_write = skin_alloc_element();
skin_parse_newline(*to_write, &cursor);
if(!last)
return NULL;
}
else if(sublines)
{
*to_write = skin_parse_sublines(&cursor);
last = *to_write;
@ -202,23 +209,6 @@ struct skin_element* skin_parse_line_optional(char** document, int conditional)
}
}
if(*cursor == '\n')
{
/* Allocating memory if necessary */
if(root)
{
current->next = skin_alloc_element();
current = current->next;
}
else
{
current = skin_alloc_element();
root = current;
}
if(!skin_parse_newline(current, &cursor))
return NULL;
}
/* Moving up the calling function's pointer */
*document = cursor;

View file

@ -36,13 +36,13 @@ extern char skin_parse_tree[];
/* Possible types of element in a WPS file */
enum skin_element_type
{
TEXT,
NEWLINE,
COMMENT,
TAG,
CONDITIONAL,
LINE,
SUBLINES,
LINE
CONDITIONAL,
TAG,
NEWLINE,
TEXT,
COMMENT,
};
enum skin_errorcode