Commit 82c1c10e authored by Victor Yacovlev's avatar Victor Yacovlev

Initial record type support

parent 3d6242ec
......@@ -61,6 +61,8 @@ def name_to_cpp(name, firstUpper = False):
return "OperatorLESS"
elif ascii==">":
return "OperatorGREATER"
elif ascii.startswith(":="):
return "OperatorASSIGN"
for c in ascii:
if c==' ':
nextIsCap = True
......@@ -95,8 +97,8 @@ def basetype_to_qtype(baseType):
p = typename.index("{")
typename = typename[6:p]
return typename
else:
return baseType
return baseType
def vector_type(baseType): return "QVector< "+baseType+" >"
......@@ -125,6 +127,51 @@ actorCPPModuleName = name_to_cpp(actor["name"], firstUpper=True)+"Module"
hName = actorCPPModuleName.lower()+"base.h"
cppName = actorCPPModuleName.lower()+"base.cpp"
handlesCustomTypeConstant = "false"
if "types" in actor.keys():
for tp in actor["types"]:
if "constants" in tp and (tp["constants"]==True or tp["constants"]==1):
handlesCustomTypeConstant = "true"
break
parseCustomTypeConstantBody = " Q_UNUSED(typeName); Q_UNUSED(literal);\n"
parseCustomConstantH = ""
parseCustomConstantHB = ""
parseCustomConstantCPP = ""
if handlesCustomTypeConstant:
firstIf = True
parseCustomTypeConstantBody = ""
for tp in actor["types"]:
typename = tp["cppdecl"]
if typename.startswith("struct "):
p = typename.index("{")
typename = typename[7:p]
if typename.startswith("class "):
p = typename.index("{")
typename = typename[6:p]
typename = typename.strip()
if "constants" in tp.keys() and (tp["constants"]==True or tp["constants"]==1):
methodName = "parseConstantOfType_"+typename
if firstIf:
firstIf = False
parseCustomTypeConstantBody += "if "
else:
parseCustomTypeConstantBody += " else if "
parseCustomTypeConstantBody += "( literal==QString::fromAscii(\"%s\") ) {\n" % typename
parseCustomTypeConstantBody += " %s value;\n" % typename
parseCustomTypeConstantBody += " if ( m_module->%s(literal, value) ) {\n" % methodName
parseCustomTypeConstantBody += " char data[sizeof(%s)];\n" % typename
parseCustomTypeConstantBody += " memcpy(data, &value, sizeof(value));\n"
parseCustomTypeConstantBody += " result = QByteArray(data);\n"
parseCustomTypeConstantBody += " }\n"
parseCustomTypeConstantBody += " }\n"
parseCustomConstantH += " bool "+methodName+"(const QString & literal, "+typename+" &value);\n"
parseCustomConstantHB += " virtual bool "+methodName+"(const QString & literal, "+typename+" &value) = 0;\n"
parseCustomConstantCPP += "bool "+actorCPPModuleName+"::"+methodName+"(const QString & literal, "+typename+" &value) {\n //TODO implement me\n return false;\n}\n"
DO_NOT_EDIT = """/*
DO NOT EDIT THIS FILE!
......@@ -154,6 +201,7 @@ if update:
h.write(" Q_OBJECT\n")
h.write("public:\n")
h.write(" %sBase(ExtensionSystem::KPlugin * parent);\n" % actorCPPModuleName)
h.write(parseCustomConstantHB)
h.write("public slots:\n")
h.write(" // Reset actor state before program starts\n")
h.write(" virtual void reset() = 0;\n")
......@@ -239,6 +287,9 @@ def scan_actons(rootName, items):
scan_actons(name, item["items"])
else:
h.write(" QAction* "+name+";\n")
if update:
scan_actons("m_action", menus)
......@@ -351,6 +402,7 @@ void $className::setAnimationEnabled(bool enabled)
Q_UNUSED(enabled);
}
""".\
replace("$className",name_to_cpp(actor["name"],True)+"ModuleBase").\
replace("$pluginClassName",name_to_cpp(actor["name"],True)+"Plugin")
......@@ -391,41 +443,42 @@ if actor.has_key("gui"):
except:
pultIconName = ""
if update:
h = open(hName, "w")
h.write(DO_NOT_EDIT)
h.write("""
#ifndef %s
#define %s
#ifndef $hFileIfdef
#define $hFileIfdef
#include <QtCore>
#include <QtGui>
#include "extensionsystem/kplugin.h"
#include "extensionsystem/declarativesettingspage.h"
#include "interfaces/actorinterface.h"
namespace %s {
namespace $namespace {
class %s
class $pluginClassName
: public ExtensionSystem::KPlugin
, public Shared::ActorInterface
{
friend class %s;
friend class %s;
friend class $baseClassName;
friend class $asyncRunThreadName;
Q_OBJECT
Q_INTERFACES(Shared::ActorInterface)
public:
// Constructor
%s();
$pluginClassName();
// Generic plugin information
inline bool isGuiRequired() const { return %s; }
inline bool isGuiRequired() const { return $guiRequired; }
// Actor information
QStringList funcList() const;
TypeList typeList() const;
QString name() const;
inline QString mainIconName() const { return "%s"; }
inline QString pultIconName() const { return "%s"; }
inline QString mainIconName() const { return "$mainIconName"; }
inline QString pultIconName() const { return "$pultIconName"; }
inline virtual bool handlesCustomTypeConstant() const { return $handlesCustomTypeConstant; }
virtual QByteArray parseCustomTypeConstant(const QString & /*asciiTypeName*/,
const QString & /*literal*/) const;
// Actor GUI access
QWidget* mainWidget();
QWidget* pultWidget();
......@@ -490,8 +543,8 @@ private:
return result;
}
void updateSettings();
class %s* m_module;
%s
class $baseClassName* m_module;
$asyncClassDecl
QString s_errorText;
QVariant v_result;
QVariantList l_optResults;
......@@ -500,24 +553,22 @@ signals:
void sync();
};
} // %s
#endif // %s
""" % (
hIfnDef, hIfnDef,
actorCPPNameSpace,
actorCPPName+"Plugin",
actorCPPName+"ModuleBase",
actorCPPName+"AsyncRunThread",
actorCPPName+"Plugin",
actorHasGui,
mainIconName,
pultIconName,
actorCPPName+"ModuleBase",
asyncClassDecl,
actorCPPNameSpace,
hIfnDef
))
} // $namespace
#endif // $hFileIfdef
"""
.replace("$hFileIfdef", hIfnDef)
.replace("$namespace", actorCPPNameSpace)
.replace("$pluginClassName", actorCPPName+"Plugin")
.replace("$baseClassName", actorCPPName+"ModuleBase")
.replace("$asyncRunThreadName", actorCPPName+"AsyncRunThread")
.replace("$guiRequired", actorHasGui)
.replace("$mainIconName", mainIconName)
.replace("$pultIconName", pultIconName)
.replace("$asyncClassDecl", asyncClassDecl)
.replace("$handlesCustomTypeConstant", handlesCustomTypeConstant)
.encode("utf8")
)
h.close()
......@@ -760,6 +811,9 @@ if "types" in actor.keys():
typename = typename[6:p]
kum_name = kumir_custom_typename(name)
makeTypes += " tp = Shared::ActorInterface::CustomType(QString::fromUtf8(\""+kum_name+"\"), sizeof("+typename+"));\n"
makeTypes += " result << tp;\n"
if update:
cpp = open(cppName, "w")
......@@ -841,6 +895,13 @@ Shared::ActorInterface::TypeList $className::typeList() const
return result;
}
QByteArray $className::parseCustomTypeConstant(const QString & typeName, const QString & literal) const
{
QByteArray result;
$parseCustomTypeConstantBody
return result;
}
QString $className::name() const
{
return QString::fromUtf8(\"$actorName\");
......@@ -967,6 +1028,7 @@ Q_EXPORT_PLUGIN($namespace::$className)
.replace("$actorName", actor["name"]["ru_RU"])
.replace("$settingsPageCreation", settingsPageCreation)
.replace("$makeTypes", makeTypes)
.replace("$parseCustomTypeConstantBody", parseCustomTypeConstantBody)
.encode("utf-8")
)
cpp.close()
......@@ -1040,7 +1102,9 @@ class $className
Q_OBJECT
public:
// Constructor
$className(ExtensionSystem::KPlugin * parent);
$constantParser
public slots:
// Reset actor state before program starts
void reset();
......@@ -1064,6 +1128,7 @@ $settingsIfNeed
.replace("$guiIfNeed", guiIfNeed)
.replace("$methods", actorMethodsForHeader)
.replace("$settingsIfNeed", settingsIfNeed)
.replace("$constantParser", parseCustomConstantH)
)
h.close()
......@@ -1104,10 +1169,13 @@ void $className::setAnimationEnabled(bool enabled)
*/
}
$constantsParsers
"""
.replace("$classHeader", className.lower()+".h")
.replace("$namespace", actorCPPNameSpace)
.replace("$className", className)
.replace("$constantsParsers", parseCustomConstantCPP)
)
if windows.has_key("main"):
......
......@@ -4,8 +4,7 @@
{
"name": { "ascii": "complex", "ru_RU": "компл" },
"cppdecl": "struct Complex { double re; double im; }",
"constants": true,
"convertertable from": ["double", "int"]
"constants": true
}
],
"methods": [
......@@ -54,6 +53,20 @@
{ "name": "x", "baseType": "complex" },
{ "name": "y", "baseType": "complex" }
]
}
},
{
"name": ":=",
"returnType": "complex",
"arguments": [
{ "name": "x", "baseType": "int" }
]
},
{
"name": ":=",
"returnType": "complex",
"arguments": [
{ "name": "x", "baseType": "double" }
]
}
]
}
......@@ -34,6 +34,12 @@ void ComplexNumbersModule::setAnimationEnabled(bool enabled)
*/
}
bool ComplexNumbersModule::parseConstantOfType_Complex(const QString & literal, Complex &value) {
//TODO implement me
return false;
}
qreal ComplexNumbersModule::runRe(const Complex & x)
{
......@@ -76,5 +82,19 @@ Complex ComplexNumbersModule::runOperatorSLASH(const Complex & x, const Complex
return Complex ();
}
Complex ComplexNumbersModule::runOperatorASSIGN(const int x)
{
/* TODO implement me */
return Complex ();
}
Complex ComplexNumbersModule::runOperatorASSIGN(const qreal x)
{
/* TODO implement me */
return Complex ();
}
} // $namespace
......@@ -22,7 +22,10 @@ class ComplexNumbersModule
Q_OBJECT
public:
// Constructor
ComplexNumbersModule(ExtensionSystem::KPlugin * parent);
bool parseConstantOfType_Complex(const QString & literal, Complex &value);
public slots:
// Reset actor state before program starts
void reset();
......@@ -35,6 +38,8 @@ public slots:
Complex runOperatorMINUS(const Complex & x, const Complex & y);
Complex runOperatorASTERISK(const Complex & x, const Complex & y);
Complex runOperatorSLASH(const Complex & x, const Complex & y);
Complex runOperatorASSIGN(const int x);
Complex runOperatorASSIGN(const qreal x);
......
......@@ -166,7 +166,7 @@ void AnalizerPrivate::setHiddenText(const QString &text, int baseLineNo)
// Build tables for hidden algorhitms
analizer->init(teacherStatements, ast, 0);
analizer->buildTables();
analizer->buildTables(false);
// Do complete semantic analisys
QList<Statement*> statementsToAnalize = statements+teacherStatements;
......@@ -338,15 +338,31 @@ void AnalizerPrivate::createModuleFromActor(const Shared::ActorInterface * actor
mod->builtInID = forcedId;
mod->header.type = AST::ModTypeExternal;
mod->header.name = actor->name();
mod->header.enabled = AlwaysAvailableModulesName.contains(mod->header.name);
mod->header.enabled = true;
ast->modules << mod;
for (int i=0; i<actor->typeList().size(); i++) {
Shared::ActorInterface::CustomType ct = actor->typeList()[i];
typedef Shared::ActorInterface AI;
AI::CustomType ct = actor->typeList()[i];
AST::Type tp;
tp.name = ct.first;
tp.size = ct.second;
AI::Record record = ct.second;
for (int j=0; j<record.size(); j++) {
AI::Field field = record[j];
AI::FieldType ft = field.second;
AST::Type afield;
if (ft==AI::Int)
afield.kind = AST::TypeInteger;
else if (ft==AI::Real)
afield.kind = AST::TypeReal;
else if (ft==AI::Bool)
afield.kind = AST::TypeBoolean;
else if (ft==AI::Char)
afield.kind = AST::TypeCharect;
else if (ft==AI::String)
afield.kind = AST::TypeString;
tp.userTypeFields << AST::Field(field.first, afield);
}
tp.kind = AST::TypeUser;
mod->header.types << tp;
}
......@@ -365,7 +381,7 @@ void AnalizerPrivate::createModuleFromActor(const Shared::ActorInterface * actor
sts[0]->alg = alg;
sts[0]->mod = mod;
analizer->init(sts, ast, alg);
analizer->buildTables();
analizer->buildTables(true);
foreach (const Lexem *lx, sts[0]->data) {
if (!lx->error.isEmpty()) {
Q_ASSERT_X(sts.size()==1
......@@ -376,6 +392,7 @@ void AnalizerPrivate::createModuleFromActor(const Shared::ActorInterface * actor
}
delete sts[0];
}
mod->header.enabled = AlwaysAvailableModulesName.contains(mod->header.name);
}
extern AnalizerPrivate::AnalizeSubject operator * ( const AnalizerPrivate::AnalizeSubject &first
......@@ -803,7 +820,7 @@ void AnalizerPrivate::doCompilation(AnalizeSubject whatToCompile
}
analizer->init(analizingStatements, ast, alg);
if (whatToCompile!=SubjStatements)
analizer->buildTables();
analizer->buildTables(false);
analizer->processAnalisys();
analizer->syncStatements();
......
......@@ -71,9 +71,12 @@ class Files
// (check system locale)
TypeList result;
CustomType fileType;
fileType.first = QString::fromUtf8("файл");
fileType.second = sizeof(Kumir::FileType);
Field fileKey(QString::fromAscii("key"), Int);
Field openMode(QString::fromAscii("mode"), Int);
Field fileName(QString::fromAscii("name"), String);
Record fileRecord;
fileRecord << fileKey << openMode << fileName;
CustomType fileType(QString::fromUtf8("файл"), fileRecord);
result << fileType;
return result;
}
......
......@@ -39,7 +39,7 @@ struct SyntaxAnalizerPrivate
void parseImport(int str);
void parseModuleHeader(int str);
void parseAlgHeader(int str, bool onlyName);
void parseAlgHeader(int str, bool onlyName, bool allowOperatorsDeclaration);
void parseVarDecl(int str);
void parseAssignment(int str);
void parseInputOutput(int str);
......@@ -50,7 +50,14 @@ struct SyntaxAnalizerPrivate
void parseIfCase(int str);
void parseLoopBegin(int str);
void parseAssignFileStream(int str);
bool findConversionAlgorithm(const AST::Type & from
, const AST::Type & to
, AST::Module * mod
, AST::Algorhitm * alg) const;
AST::Expression * makeCustomBinaryOperation(const QString & operatorName
, AST::Expression * leftExpression
, AST::Expression * rightExpression
);
bool findAlgorhitm(const QString &name
, const AST::Module* module
, AST::Algorhitm* & algorhitm);
......@@ -178,7 +185,7 @@ Lexem * SyntaxAnalizerPrivate::findLexemByType(const QList<Lexem*> lxs, LexemTyp
return 0;
}
void SyntaxAnalizer::buildTables()
void SyntaxAnalizer::buildTables(bool allowOperatorsDeclaration)
{
// if (d->algorhitm)
// return; // Nothing to build if we analize just one algorhitm
......@@ -263,7 +270,7 @@ void SyntaxAnalizer::buildTables()
const Statement & st = d->statements[i];
bool wasError = st.hasError();
if (st.type==LxPriAlgHeader) {
d->parseAlgHeader(i, true);
d->parseAlgHeader(i, true, allowOperatorsDeclaration);
}
if (!wasError && d->statements[i].hasError()) {
foreach (Lexem * lx, d->statements[i].data) {
......@@ -280,7 +287,7 @@ void SyntaxAnalizer::buildTables()
d->parseVarDecl(i);
}
if (st.type==LxPriAlgHeader) {
d->parseAlgHeader(i, false);
d->parseAlgHeader(i, false, allowOperatorsDeclaration);
}
if (!wasError && d->statements[i].hasError()) {
foreach (Lexem * lx, d->statements[i].data) {
......@@ -1537,7 +1544,7 @@ void SyntaxAnalizerPrivate::parseAssignment(int str)
st.statement->expressions << leftExpr;
}
void SyntaxAnalizerPrivate::parseAlgHeader(int str, bool onlyName)
void SyntaxAnalizerPrivate::parseAlgHeader(int str, bool onlyName, bool allowOperatorsDeclaration)
{
const Statement & st = statements[str];
if (st.hasError() || !st.mod ||!st.alg)
......@@ -1547,6 +1554,7 @@ void SyntaxAnalizerPrivate::parseAlgHeader(int str, bool onlyName)
Q_CHECK_PTR(alg);
Q_CHECK_PTR(mod);
QString name;
bool isOperator = false;
bool isFirst = mod->header.name.isEmpty() && mod->impl.algorhitms.indexOf(alg)==0;
int argsStartLexem = -1;
int nameStartLexem = 1;
......@@ -1587,7 +1595,13 @@ void SyntaxAnalizerPrivate::parseAlgHeader(int str, bool onlyName)
argsStartLexem = i+1;
break;
}
else if (st.data[i]->type==LxNameClass
else if (allowOperatorsDeclaration) {
if (i>nameStartLexem)
name += " ";
name += st.data[i]->data;
isOperator = true;
}
else if (st.data[i]->type==LxNameClass
|| st.data[i]->type & LxTypePrimaryKwd
|| st.data[i]->type & LxTypeSecondaryKwd)
{
......@@ -1632,7 +1646,7 @@ void SyntaxAnalizerPrivate::parseAlgHeader(int str, bool onlyName)
// Проверяем на повторное описание алгоритма
AST::Algorhitm * aa;
if (findAlgorhitm(name,st.mod,aa) && aa!=alg)
if (!isOperator && findAlgorhitm(name,st.mod,aa) && aa!=alg)
{
for (int i=1; i<st.data.size(); i++) {
if (st.data[i]->type==LxNameAlg)
......@@ -1644,7 +1658,7 @@ void SyntaxAnalizerPrivate::parseAlgHeader(int str, bool onlyName)
// Проверяем на наличие переменной с таким же именем
AST::Variable * vv;
if (findGlobalVariable(name, st.mod, vv)) {
if (!isOperator && findGlobalVariable(name, st.mod, vv)) {
for (int i=1; i<st.data.size(); i++) {
if (st.data[i]->type==LxNameAlg)
st.data[i]->error = _("The name is used by global variable");
......@@ -1670,7 +1684,10 @@ void SyntaxAnalizerPrivate::parseAlgHeader(int str, bool onlyName)
// Make this algorhitm public available (if not private name)
if (!name.isEmpty() && !name.startsWith("_")) {
mod->header.algorhitms << alg;
if (isOperator)
mod->header.operators << alg;
else
mod->header.algorhitms << alg;
}
for (int i=nameStartLexem; i<argsStartLexem-1; i++) {
......@@ -1687,7 +1704,7 @@ void SyntaxAnalizerPrivate::parseAlgHeader(int str, bool onlyName)
return;
}
// =============== � АЗБО� А� ГУМЕНТОВ
// =============== Argument list parsing
QList<VariablesGroup> groups;
......@@ -1890,9 +1907,7 @@ QList<AST::Variable*> SyntaxAnalizerPrivate::parseVariables(int statementIndex,
AST::Type userType;
AST::Module * userTypeModule = 0;
if (findUserType(group.lexems[curPos]->data, userType, userTypeModule)) {
cType.kind = AST::TypeUser;
cType.name = group.lexems[curPos]->data;
cType.size = userType.size;
cType = userType;
}
}
else {
......@@ -2719,6 +2734,101 @@ bool SyntaxAnalizerPrivate::findAlgorhitm(const QString &name, const AST::Module
return false;
}
bool SyntaxAnalizerPrivate::findConversionAlgorithm(const AST::Type & from
, const AST::Type & to
, AST::Module * mod
, AST::Algorhitm * alg) const
{
for (int i=0; i<ast->modules.size(); i++) {
mod = ast->modules[i];
if (!mod->header.enabled)
continue;
for (int j=0; j<mod->header.operators.size(); j++) {
alg = mod->header.operators[j];
if (alg->header.arguments.size()==1) {
if (alg->header.arguments[0]->baseType==from
&& alg->header.arguments[0]->dimension==0)
{
if (alg->header.returnType==to)
return true;
}
}
}
}
mod = 0;
alg = 0;
return false;
}
AST::Expression * SyntaxAnalizerPrivate::makeCustomBinaryOperation(const QString & operatorName
, AST::Expression * leftExpression
, AST::Expression * rightExpression
)
{
QString headTypeName;
if (leftExpression->baseType.kind==AST::TypeUser)
headTypeName = leftExpression->baseType.name;
else
headTypeName = lexer->classNameByBaseType(leftExpression->baseType.kind);
QString tailTypeName;
if (rightExpression->baseType.kind==AST::TypeUser)
tailTypeName = rightExpression->baseType.name;
else
tailTypeName = lexer->classNameByBaseType(rightExpression->baseType.kind);
for (int i=0; i<ast->modules.size(); i++) {