Skip to content

Commit 01954b7

Browse files
committed
More work
1 parent f4f15f5 commit 01954b7

3 files changed

Lines changed: 433 additions & 88 deletions

File tree

modules/yup_data_model/tree/yup_DataTreeQuery.cpp

Lines changed: 101 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -255,14 +255,15 @@ struct DataTreeQuery::XPathParser
255255
{
256256
// Property selection
257257
++currentToken;
258-
if (currentToken < static_cast<int> (tokens.size()) && tokens[currentToken].type == Token::Type::Identifier)
258+
if (currentToken < static_cast<int> (tokens.size()) &&
259+
(tokens[currentToken].type == Token::Type::Identifier || tokens[currentToken].type == Token::Type::Function))
259260
{
260261
operations.emplace_back (QueryOperation::Property, tokens[currentToken].value);
261262
++currentToken;
262263
}
263264
else
264265
{
265-
// Error: @ not followed by identifier
266+
// Error: @ not followed by identifier or function name
266267
parseResult = Result::fail ("Expected property name after '@' in node test");
267268
return;
268269
}
@@ -419,105 +420,100 @@ struct DataTreeQuery::XPathParser
419420
else if (token.type == Token::Type::Function)
420421
{
421422
++currentToken;
423+
std::unique_ptr<Predicate> pred;
424+
425+
auto skipParenthesis = [&]
426+
{
427+
if (currentToken < static_cast<int> (tokens.size()) && tokens[currentToken].type == Token::Type::OpenParen)
428+
{
429+
++currentToken;
430+
if (currentToken < static_cast<int> (tokens.size()) && tokens[currentToken].type == Token::Type::CloseParen)
431+
++currentToken;
432+
}
433+
};
422434

423435
if (token.value == "first")
424436
{
437+
skipParenthesis();
425438
return std::make_unique<Predicate> (Predicate::First);
426439
}
427440
else if (token.value == "last")
428441
{
442+
skipParenthesis();
429443
return std::make_unique<Predicate> (Predicate::Last);
430444
}
431445
else if (token.value == "position")
432446
{
433-
// Skip parentheses for position()
434-
if (currentToken < static_cast<int> (tokens.size()) && tokens[currentToken].type == Token::Type::OpenParen)
435-
{
436-
++currentToken;
437-
if (currentToken < static_cast<int> (tokens.size()) && tokens[currentToken].type == Token::Type::CloseParen)
438-
++currentToken;
439-
}
440-
441-
// For now, treat position() as position(1) - could be enhanced
447+
skipParenthesis();
442448
return std::make_unique<Predicate> (Predicate::Position, 1);
443449
}
444450
}
445451
else if (token.type == Token::Type::AtSign)
446452
{
447453
++currentToken;
448-
if (currentToken < static_cast<int> (tokens.size()) && tokens[currentToken].type == Token::Type::Identifier)
454+
if (currentToken < static_cast<int> (tokens.size()) &&
455+
(tokens[currentToken].type == Token::Type::Identifier || tokens[currentToken].type == Token::Type::Function))
449456
{
450457
String propertyName = tokens[currentToken].value;
451458
++currentToken;
452459

460+
auto parseAndValidateValue = [&]
461+
{
462+
++currentToken;
463+
auto value = parseValue();
464+
if (! isValidValue (value))
465+
{
466+
parseResult = Result::fail ("Expected value after comparison operator");
467+
return var();
468+
}
469+
470+
return value;
471+
};
472+
453473
// Check for equality/inequality
454474
if (currentToken < static_cast<int> (tokens.size()))
455475
{
456476
if (tokens[currentToken].type == Token::Type::Equal)
457477
{
458-
++currentToken;
459-
auto value = parseValue();
460-
if (! isValidValue (value))
461-
{
462-
parseResult = Result::fail ("Expected value after comparison operator");
463-
return nullptr;
464-
}
465-
return std::make_unique<Predicate> (Predicate::PropertyEquals, propertyName, value);
478+
if (auto value = parseAndValidateValue(); ! value.isVoid())
479+
return std::make_unique<Predicate> (Predicate::PropertyEquals, propertyName, value);
480+
481+
return nullptr;
466482
}
467483
else if (tokens[currentToken].type == Token::Type::NotEqual)
468484
{
469-
++currentToken;
470-
auto value = parseValue();
471-
if (! isValidValue (value))
472-
{
473-
parseResult = Result::fail ("Expected value after comparison operator");
474-
return nullptr;
475-
}
476-
return std::make_unique<Predicate> (Predicate::PropertyNotEquals, propertyName, value);
485+
if (auto value = parseAndValidateValue(); ! value.isVoid())
486+
return std::make_unique<Predicate> (Predicate::PropertyNotEquals, propertyName, value);
487+
488+
return nullptr;
477489
}
478490
else if (tokens[currentToken].type == Token::Type::Greater)
479491
{
480-
++currentToken;
481-
auto value = parseValue();
482-
if (! isValidValue (value))
483-
{
484-
parseResult = Result::fail ("Expected value after comparison operator");
485-
return nullptr;
486-
}
487-
return std::make_unique<Predicate> (Predicate::PropertyGreater, propertyName, value);
492+
if (auto value = parseAndValidateValue(); ! value.isVoid())
493+
return std::make_unique<Predicate> (Predicate::PropertyGreater, propertyName, value);
494+
495+
return nullptr;
488496
}
489497
else if (tokens[currentToken].type == Token::Type::Less)
490498
{
491-
++currentToken;
492-
auto value = parseValue();
493-
if (! isValidValue (value))
494-
{
495-
parseResult = Result::fail ("Expected value after comparison operator");
496-
return nullptr;
497-
}
498-
return std::make_unique<Predicate> (Predicate::PropertyLess, propertyName, value);
499+
if (auto value = parseAndValidateValue(); ! value.isVoid())
500+
return std::make_unique<Predicate> (Predicate::PropertyLess, propertyName, value);
501+
502+
return nullptr;
499503
}
500504
else if (tokens[currentToken].type == Token::Type::GreaterEqual)
501505
{
502-
++currentToken;
503-
auto value = parseValue();
504-
if (! isValidValue (value))
505-
{
506-
parseResult = Result::fail ("Expected value after comparison operator");
507-
return nullptr;
508-
}
509-
return std::make_unique<Predicate> (Predicate::PropertyGreaterEqual, propertyName, value);
506+
if (auto value = parseAndValidateValue(); ! value.isVoid())
507+
return std::make_unique<Predicate> (Predicate::PropertyGreaterEqual, propertyName, value);
508+
509+
return nullptr;
510510
}
511511
else if (tokens[currentToken].type == Token::Type::LessEqual)
512512
{
513-
++currentToken;
514-
auto value = parseValue();
515-
if (! isValidValue (value))
516-
{
517-
parseResult = Result::fail ("Expected value after comparison operator");
518-
return nullptr;
519-
}
520-
return std::make_unique<Predicate> (Predicate::PropertyLessEqual, propertyName, value);
513+
if (auto value = parseAndValidateValue(); ! value.isVoid())
514+
return std::make_unique<Predicate> (Predicate::PropertyLessEqual, propertyName, value);
515+
516+
return nullptr;
521517
}
522518
}
523519

@@ -526,7 +522,7 @@ struct DataTreeQuery::XPathParser
526522
}
527523
else
528524
{
529-
// Error: @ not followed by identifier in predicate
525+
// Error: @ not followed by identifier or function name in predicate
530526
parseResult = Result::fail ("Expected property name after '@' in predicate");
531527
return nullptr;
532528
}
@@ -704,40 +700,61 @@ struct DataTreeQuery::XPathParser
704700
break;
705701

706702
case '!':
707-
if (pos + 1 < input.length() && input[pos + 1] == '=')
708-
{
709-
tokens.emplace_back (Token::Type::NotEqual, tokenStart);
710-
pos += 2;
711-
}
712-
else
713703
{
714-
++pos; // Skip invalid character
704+
// Check for != with optional whitespace
705+
int nextPos = pos + 1;
706+
while (nextPos < input.length() && std::isspace (input[nextPos]))
707+
++nextPos;
708+
709+
if (nextPos < input.length() && input[nextPos] == '=')
710+
{
711+
tokens.emplace_back (Token::Type::NotEqual, tokenStart);
712+
pos = nextPos + 1; // Move past the '='
713+
}
714+
else
715+
{
716+
++pos; // Skip invalid character
717+
}
715718
}
716719
break;
717720

718721
case '>':
719-
if (pos + 1 < input.length() && input[pos + 1] == '=')
720722
{
721-
tokens.emplace_back (Token::Type::GreaterEqual, tokenStart);
722-
pos += 2;
723-
}
724-
else
725-
{
726-
tokens.emplace_back (Token::Type::Greater, tokenStart);
727-
++pos;
723+
// Check for >= with optional whitespace
724+
int nextPos = pos + 1;
725+
while (nextPos < input.length() && std::isspace (input[nextPos]))
726+
++nextPos;
727+
728+
if (nextPos < input.length() && input[nextPos] == '=')
729+
{
730+
tokens.emplace_back (Token::Type::GreaterEqual, tokenStart);
731+
pos = nextPos + 1; // Move past the '='
732+
}
733+
else
734+
{
735+
tokens.emplace_back (Token::Type::Greater, tokenStart);
736+
++pos; // Just move past '>'
737+
}
728738
}
729739
break;
730740

731741
case '<':
732-
if (pos + 1 < input.length() && input[pos + 1] == '=')
733742
{
734-
tokens.emplace_back (Token::Type::LessEqual, tokenStart);
735-
pos += 2;
736-
}
737-
else
738-
{
739-
tokens.emplace_back (Token::Type::Less, tokenStart);
740-
++pos;
743+
// Check for <= with optional whitespace
744+
int nextPos = pos + 1;
745+
while (nextPos < input.length() && std::isspace (input[nextPos]))
746+
++nextPos;
747+
748+
if (nextPos < input.length() && input[nextPos] == '=')
749+
{
750+
tokens.emplace_back (Token::Type::LessEqual, tokenStart);
751+
pos = nextPos + 1; // Move past the '='
752+
}
753+
else
754+
{
755+
tokens.emplace_back (Token::Type::Less, tokenStart);
756+
++pos; // Just move past '<'
757+
}
741758
}
742759
break;
743760

modules/yup_data_model/tree/yup_DataTreeSchema.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -478,13 +478,17 @@ Result DataTreeSchema::validateValueAgainstSchema (const var& value, const Prope
478478
// Type validation
479479
if (schema.type == "string" && ! value.isString())
480480
return Result::fail ("Property '" + propertyName + "' must be a string");
481-
else if (schema.type == "number" && ! value.isDouble() && ! value.isInt())
481+
482+
if (schema.type == "number" && ! value.isDouble() && ! value.isInt())
482483
return Result::fail ("Property '" + propertyName + "' must be a number");
483-
else if (schema.type == "boolean" && ! value.isBool())
484+
485+
if (schema.type == "boolean" && ! value.isBool())
484486
return Result::fail ("Property '" + propertyName + "' must be a boolean");
485-
else if (schema.type == "array" && ! value.isArray())
487+
488+
if (schema.type == "array" && ! value.isArray())
486489
return Result::fail ("Property '" + propertyName + "' must be an array");
487-
else if (schema.type == "object" && ! value.isObject())
490+
491+
if (schema.type == "object" && ! value.isObject())
488492
return Result::fail ("Property '" + propertyName + "' must be an object");
489493

490494
// Enum validation
@@ -499,6 +503,7 @@ Result DataTreeSchema::validateValueAgainstSchema (const var& value, const Prope
499503
break;
500504
}
501505
}
506+
502507
if (! found)
503508
return Result::fail ("Property '" + propertyName + "' must be one of the allowed values");
504509
}

0 commit comments

Comments
 (0)