From 3ced433bc45aade14625a2ba178d806e7ee196c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Mon, 6 Jan 2014 10:54:46 +0200 Subject: [PATCH] Script|libdeng2: Creating records with expressions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously it was only possible to create a new record using the “record” statement or the Record() function. This commit makes it possible to put “record” in front of any expression that refers to an identifier, and that identifier will be created as a (sub)record. For instance:
# Old way:
record a
a.b = 1
record a.sub
# Alternatively: a.sub = Record()
a.sub.c = 2

# New way:
(record a).b = 1
a.(record sub).c = 2
--- .../libdeng2/src/scriptsys/nameexpression.cpp | 2 +- doomsday/libdeng2/src/scriptsys/parser.cpp | 30 +++++++++++++++++-- doomsday/tests/test_script/kitchen_sink.de | 9 +++++- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/doomsday/libdeng2/src/scriptsys/nameexpression.cpp b/doomsday/libdeng2/src/scriptsys/nameexpression.cpp index 8315412e32..3df91c292c 100644 --- a/doomsday/libdeng2/src/scriptsys/nameexpression.cpp +++ b/doomsday/libdeng2/src/scriptsys/nameexpression.cpp @@ -46,7 +46,7 @@ Value *NameExpression::evaluate(Evaluator &evaluator) const { //LOG_AS("NameExpression::evaluate"); //std::cout << "NameExpression::evaluator: " << _flags.to_string() << "\n"; - //LOG_DEBUG("path = %s, scope = %x") << _path << evaluator.names(); + LOGDEV_SCR_XVERBOSE_DEBUGONLY("evaluating name:\"%s\" flags:%x", _identifier << flags()); // Collect the namespaces to search. Evaluator::Namespaces spaces; diff --git a/doomsday/libdeng2/src/scriptsys/parser.cpp b/doomsday/libdeng2/src/scriptsys/parser.cpp index 926fe6358b..2c0ecf3c77 100644 --- a/doomsday/libdeng2/src/scriptsys/parser.cpp +++ b/doomsday/libdeng2/src/scriptsys/parser.cpp @@ -619,7 +619,7 @@ Expression *Parser::parseExpression(TokenRange const &fullRange, Expression::Fla TokenRange range = fullRange; LOG_AS("parseExpression"); - LOGDEV_SCR_XVERBOSE_DEBUGONLY("", range.asText()); + LOGDEV_SCR_XVERBOSE_DEBUGONLY("%s (flags:%x)", range.asText() << flags); if(!range.size()) { @@ -633,6 +633,21 @@ Expression *Parser::parseExpression(TokenRange const &fullRange, Expression::Fla range = range.shrink(1); } + // Do we have a record declaration in the expression? + if(range.firstToken().type() == Token::KEYWORD && + range.firstToken().equals(ScriptLex::RECORD)) + { + LOGDEV_SCR_XVERBOSE_DEBUGONLY("declaration expression: RECORD %s", range.startingFrom(1).asText()); + + if(range.size() == 1) + { + throw MissingTokenError("Parser::parseDeclarationExpression", + "Expected identifier to follow " + range.firstToken().asText()); + } + return parseExpression(range.startingFrom(1), + flags | Expression::LocalOnly | Expression::NewSubrecord); + } + TokenRange leftSide = range.between(0, 0); TokenRange rightSide = leftSide; @@ -673,7 +688,7 @@ ArrayExpression *Parser::parseArrayExpression(TokenRange const &range) "Expected brackets for the array expression beginning at " + range.firstToken().asText()); } - return parseList(range.between(1, range.size() - 1)); + return parseList(range.shrink(1)); } DictionaryExpression *Parser::parseDictionaryExpression(TokenRange const &range) @@ -791,7 +806,16 @@ OperatorExpression *Parser::parseOperatorExpression(Operator op, TokenRange cons Expression::ByReference : Expression::ByValue); Expression::Flags rightOpFlags = rightFlags; - if(op != MEMBER) rightOpFlags &= ~Expression::ByReference; + if(op == MEMBER) + { + // Don't create new variables for the left side of the member. The only place + // where a new variable is created is on the right. + leftOpFlags &= ~Expression::NewVariable; + } + else + { + rightOpFlags &= ~Expression::ByReference; + } // Binary operation. QScopedPointer leftOperand(parseExpression(leftSide, leftOpFlags)); diff --git a/doomsday/tests/test_script/kitchen_sink.de b/doomsday/tests/test_script/kitchen_sink.de index 7d94ce9665..ae37579d1b 100644 --- a/doomsday/tests/test_script/kitchen_sink.de +++ b/doomsday/tests/test_script/kitchen_sink.de @@ -449,7 +449,7 @@ end # --------------------------------------------------------------------------- sections.begin('RECORDS') -sections.subsection('Creating a record.') +sections.subsection('Creating a record with a statement.') record myrec print len(myrec) print "Alternative way using Record()." @@ -457,6 +457,13 @@ del myrec myrec = Record() print len(myrec) +sections.subsection('Creating a record using an expression.') +del myrec +(record myrec).expressionCreated = True +myrec.(record subexp).alsoExpCreated = True +print myrec +del myrec.subexp + sections.subsection('Creating variables into a record.') myrec.newMember = 100 print len(myrec)