* @brief Implements a method definition for the Abstract Syntax Tree.
*
* The special case "function" (a method without class) is included.
+ *
+ * <code>m_child</code>: body</br>
+ * <code>m_child2</code>: parameter list (or NULL)
*/
/**
* @brief Constructor.
* @param name the method name
* @param type the method result type
*/
-RplASMethod::RplASMethod(const QString& name, RplASClass* type) :
+RplASMethod::RplASMethod(const QString& name) :
RplASNode2(AST_METHOD),
m_name(name),
- m_nodeType(type)
+ m_resultType(NULL),
+ m_parent(NULL)
{
}
{
DEFINE_TABS(indent);
char buffer[256];
- fprintf(fp, "%sMethod %d %s %s(", tabs, m_id,
- m_nodeType == NULL ? "<NoneType>" : m_nodeType->name().toUtf8().constData(),
+ fprintf(fp, "%sMethod %s %s(", tabs,
+ m_resultType == NULL ? "<NoneType>" : m_resultType->name().toUtf8().constData(),
m_name.toUtf8().constData());
- fprintf(fp, ") body: %d args: %d %s\n", m_child == NULL ? 0 : m_child->id(),
+ fprintf(fp, ") id: %d parent: %d args: %d body: %d %s\n", m_id,
+ m_parent == NULL ? 0 : m_parent->id(),
m_child2 == NULL ? 0 : m_child2->id(),
+ m_child->id(),
positionStr(buffer, sizeof buffer));
+ if (m_child2 != NULL)
+ m_child2->dump(fp, indent + 1);
+ m_child->dump(fp, indent + 1);
+}
+/**
+ * @brief Returns the parent of the method: a class or a method.
+ * @return NULL: this is a function, not a method<br>
+ * otherwise: the parent: a class or a method/func
+ */
+RplASItem* RplASMethod::parent() const
+{
+ return m_parent;
}
+/**
+ * @brief Sets the parent of the method.
+ *
+ * @param parent the parent: NULL or a class or a method
+ */
+void RplASMethod::setParent(RplASItem* parent)
+{
+ m_parent = parent;
+}
+
/** @class RplASArgument rplastree.hpp "rplexpr/rplastree.hpp"
*
L_PARSE_ARGS_NO_COMMA_OR_PARENT,
L_PARSE_OPERAND_NO_FIELD2,
L_PARSE_OPERAND_NO_BRACKET2 = 2035,
- L_PARSE_OPERAND_NO_FIELD
+ L_PARSE_OPERAND_NO_FIELD,
+ L_PARSE_METH_NO_CLASS,
+ L_PARSE_METH_NO_CLASS2,
+ L_PARSE_METH_NO_NAME,
+ L_PARSE_METH_NO_NAME2 = 2040,
+ L_PARSE_METH_NO_LPARENTH,
+ L_PARSE_METH_NO_COLON,
+ L_PARSE_PARAMLIST_NO_PARENTH,
+ L_PARSE_PARAMLIST_NO_PARENTH2,
+ L_PARSE_METH_NO_END = 2045,
+ L_PARSE_METH_NO_END2
};
/** @class RplMFParser rpllexer.hpp "rplexpr/rplmfparser.hpp"
{
}
-/**
- * @brief Parses a function or a generator.
- */
-RplASItem* RplMFParser::parseFunc()
-{
- RplASItem*rc = NULL;
- return rc;
-}
/**
* @brief Parses an if statement.
*/
* @brief Parses a variable definition.
*
* Syntax:
- * Variable: { "const" | "lazy" }* <type> id [ = <expr> ] ";"
+ * Variable: { "const" | "lazy" }* <type> id [ = <expr> ] [ ";" ]
* Parameter: { "const" | "lazy" }* <type> id [ = <expr> ] { "," | ")" }
*
- * AST: RplASNamedValue
- *
- * @param clazz NULL or the type of the variable
- * @param attribute 0 or attribute of the variable: K_CONST or K_LAZY
+ * @pre first token of the definition is read
+ * @post token behind the definition is read: ';', ',', ')'
+ * @param attribute attribute of the variable: A_PARAM...
*/
-RplASItem* RplMFParser::parseVarDefinition(Keyword attribute)
+RplASItem* RplMFParser::parseVarDefinition(RplASNamedValue::Attributes attribute)
{
- RplASNamedValue::Attributes attr = RplASNamedValue::A_NONE;
+ int attributes = attribute;
RplToken* token = m_lexer.currentToken();
- while(attribute == K_CONST || attribute == K_LAZY){
- switch(attribute){
+ while(token->isKeyword(K_CONST, K_LAZY)){
+ switch(token->id()){
case K_CONST:
- attr = RplASNamedValue::A_CONST;
+ attributes += RplASNamedValue::A_CONST;
break;
case K_LAZY:
- attr = RplASNamedValue::A_LAZY;
+ attributes += RplASNamedValue::A_LAZY;
break;
default:
break;
}
token = m_lexer.nextNonSpaceToken();
- attribute = token->isTokenType(TOKEN_KEYWORD)
- ? (Keyword) token->id() : K_UNDEF;
}
if (! token->isTokenType(TOKEN_ID))
syntaxError(L_DEFINITION_NO_ID, "class name expected, but no id found");
if (! token->isTokenType(TOKEN_ID))
syntaxError(L_DEFINITION_MISSING_ID, "variable name expected");
// freed in the destructor of the nodes:
- RplASNamedValue* namedValue = new RplASNamedValue(clazz, token->toString(), attr);
+ RplASNamedValue* namedValue = new RplASNamedValue(clazz, token->toString(),
+ attributes);
namedValue->setPosition(m_lexer.currentPosition());
RplASVarDefinition* rc = new RplASVarDefinition();
rc->setPosition(m_lexer.currentPosition());
rc->setChild2(namedValue);
token = m_lexer.nextNonSpaceToken();
- if (! token->isOperator(O_ASSIGN, O_SEMICOLON))
- syntaxError(L_DEFINITION_NO_OP, "'=' or ';' expected");
if (token->id() == O_ASSIGN){
RplASItem* value = parseExpr(0);
rc->setChild3(value);
token = m_lexer.currentToken();
}
- if (! token->isOperator(O_SEMICOLON)){
- syntaxError(L_DEFINITION_NO_SEMICOLON, "';' expected");
- }
- m_lexer.nextNonSpaceToken();
return rc;
}
rc = parseExpr(level + 1);
token = m_lexer.currentToken();
if(! token->isOperator(O_RPARENT)){
- char buffer[256];
// this call never comes back (exception!)
syntaxError(L_PARSE_OPERAND_RPARENTH,
"')' expected", "(", startPosition);
return statement;
}
+RplASItem* RplMFParser::parseLocalVar(){
+ RplASItem* rc = parseVarDefinition(RplASNamedValue::A_NONE);
+ return rc;
+}
+
/**
* @brief Parses the body.
*
break;
case K_FUNCTION:
case K_GENERATOR:
- item = parseMethodDefinition();
+ item = parseMethodDefinition(NULL);
break;
case K_IMPORT:
parseImport();
break;
case K_CONST:
case K_LAZY:
- item = parseVarDefinition((Keyword) token->id());
+ item = parseLocalVar();
break;
default:
if (token->isKeyword(keywordStop, keywordStop2))
case TOKEN_ID:
{
if (token->isCapitalizedId()){
- item = parseVarDefinition(K_UNDEF);
+ item = parseLocalVar();
} else {
m_lexer.undoLastToken();
item = parseExprStatement();
return body;
}
+/**
+ * @brief Parses a parameter list of a method/function.
+ *
+ * @pre token behind '(' is read
+ * @post token behind ')' is read
+ * @return
+ */
+RplASExprStatement* RplMFParser::parseParameterList(){
+ RplASExprStatement* rc = NULL;
+ RplASExprStatement* last = NULL;
+ const RplSourcePosition* startPos = m_lexer.currentPosition();
+ RplASItem* definition;
+ do {
+ definition = parseVarDefinition(RplASNamedValue::A_PARAM);
+ RplASExprStatement *current = new RplASExprStatement();
+ current->setChild2(definition);
+ if (rc == NULL){
+ rc = current;
+ } else {
+ current->setChild(last);
+ last->setChild(current);
+ }
+ last = current;
+ } while(m_lexer.currentToken()->isOperator(O_COMMA));
+ if (! m_lexer.currentToken()->isOperator(O_RPARENT))
+ syntaxError(L_PARSE_PARAMLIST_NO_PARENTH, ") expected", ")", startPos);
+ m_lexer.nextNonSpaceToken();
+ return rc;
+}
+
/**
* @brief Parses a class definition.
+ *
+ * @pre token "func" is read
+ * @post token behind "endf" is read
* @return the node in an abstract syntax tree
*/
-RplASItem*RplMFParser::parseMethodDefinition()
+RplASMethod*RplMFParser::parseMethodDefinition(RplASItem* parent)
{
- RplASItem* rc = NULL;
+ RplASMethod* rc = NULL;
+ const RplSourcePosition* startPos = m_lexer.currentPosition();
+ RplToken* token = m_lexer.nextNonSpaceToken();
+ if (! token->isTokenType(TOKEN_ID))
+ syntaxError(L_PARSE_METH_NO_CLASS, "type name expected");
+ QString type = token->toString();
+ if (! type.at(0).isUpper())
+ syntaxError(L_PARSE_METH_NO_CLASS2,
+ "type name expected (must start with an upper case character)");
+ token = m_lexer.nextNonSpaceToken();
+ if (! token->isTokenType(TOKEN_ID))
+ syntaxError(L_PARSE_METH_NO_NAME, "method name expected");
+ QString name = token->toString();
+ if (! type.at(0).isUpper())
+ syntaxError(L_PARSE_METH_NO_CLASS2,
+ "method name expected (must start with an lower case character)");
+ token = m_lexer.nextNonSpaceToken();
+ if (! token->isOperator(O_LPARENTH, O_COLON))
+ syntaxError(L_PARSE_METH_NO_LPARENTH, "'(' or ':' expected");
+ RplASExprStatement* parameterList;
+ if (token->isOperator(O_LPARENTH)){
+ token = m_lexer.nextNonSpaceToken();
+ if (token->isOperator(O_RPARENT)){
+ token = m_lexer.nextNonSpaceToken();
+ } else {
+ parameterList = parseParameterList();
+ }
+ }
+ if (! token->isOperator(O_COLON))
+ syntaxError(L_PARSE_METH_NO_COLON, "':' expected");
+ rc = new RplASMethod(name);
+ rc->setParent(parent);
+ rc->setPosition(startPos);
+ rc->setChild2(parameterList);
+ rc->setChild(parseBody(K_ENDF));
+ if (! m_lexer.currentToken()->isKeyword(K_ENDF))
+ syntaxError(L_PARSE_METH_NO_END, "end of function not found", "endf",
+ startPos);
+ m_lexer.nextNonSpaceToken();
return rc;
}