Serenity Operating System
at master 601 lines 18 kB view raw
1/* 2 * Copyright (c) 2020, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Assertions.h> 8#include <AK/DeprecatedString.h> 9#include <AK/GenericLexer.h> 10#include <AK/NonnullOwnPtr.h> 11#include <AK/OwnPtr.h> 12#include <AK/Queue.h> 13#include <AK/StringView.h> 14#include <LibCore/System.h> 15#include <LibMain/Main.h> 16#include <LibRegex/Regex.h> 17#include <stdio.h> 18#include <unistd.h> 19 20static void print_help_and_exit() 21{ 22 outln(R"( 23Usage: expr EXPRESSION 24 expr [--help] 25 26Print the value of EXPRESSION to standard output.)"); 27 exit(0); 28} 29 30template<typename Fmt, typename... Args> 31[[noreturn]] void fail(Fmt&& fmt, Args&&... args) 32{ 33 warn("ERROR: \e[31m"); 34 warnln(StringView { fmt, strlen(fmt) }, args...); 35 warn("\e[0m"); 36 exit(2); 37} 38 39class Expression { 40public: 41 enum Precedence { 42 Or, 43 And, 44 Comp, 45 ArithS, 46 ArithM, 47 StringO, 48 Paren, 49 }; 50 static NonnullOwnPtr<Expression> parse(Queue<StringView>& args, Precedence prec = Or); 51 52 enum class Type { 53 Integer, 54 String, 55 }; 56 57 virtual bool truth() const = 0; 58 virtual int integer() const = 0; 59 virtual DeprecatedString string() const = 0; 60 virtual Type type() const = 0; 61 virtual ~Expression() = default; 62}; 63 64class ValueExpression : public Expression { 65public: 66 ValueExpression(int v) 67 : as_integer(v) 68 , m_type(Type::Integer) 69 { 70 } 71 72 ValueExpression(DeprecatedString&& v) 73 : as_string(move(v)) 74 , m_type(Type::String) 75 { 76 } 77 78 virtual ~ValueExpression() {}; 79 80private: 81 virtual bool truth() const override 82 { 83 if (m_type == Type::String) 84 return !as_string.is_empty(); 85 return integer() != 0; 86 } 87 virtual int integer() const override 88 { 89 switch (m_type) { 90 case Type::Integer: 91 return as_integer; 92 case Type::String: 93 if (auto converted = as_string.to_int(); converted.has_value()) 94 return converted.value(); 95 fail("Not an integer: '{}'", as_string); 96 } 97 VERIFY_NOT_REACHED(); 98 } 99 virtual DeprecatedString string() const override 100 { 101 switch (m_type) { 102 case Type::Integer: 103 return DeprecatedString::formatted("{}", as_integer); 104 case Type::String: 105 return as_string; 106 } 107 VERIFY_NOT_REACHED(); 108 } 109 virtual Type type() const override { return m_type; } 110 111 union { 112 int as_integer; 113 DeprecatedString as_string; 114 }; 115 Type m_type { Type::String }; 116}; 117 118class BooleanExpression : public Expression { 119public: 120 enum class BooleanOperator { 121 And, 122 Or, 123 }; 124 static BooleanOperator op_from(StringView sv) 125 { 126 if (sv == "&") 127 return BooleanOperator::And; 128 return BooleanOperator::Or; 129 } 130 BooleanExpression(BooleanOperator op, NonnullOwnPtr<Expression>&& left, NonnullOwnPtr<Expression>&& right) 131 : m_op(op) 132 , m_left(move(left)) 133 , m_right(move(right)) 134 { 135 if (m_op == BooleanOperator::Or) 136 m_left_truth = m_left->truth(); 137 else 138 m_right_truth = m_right->truth(); 139 } 140 141private: 142 virtual bool truth() const override 143 { 144 if (m_op == BooleanOperator::Or) 145 return m_left_truth ? true : m_right->truth(); 146 return m_right_truth ? m_left->truth() : false; 147 } 148 149 virtual int integer() const override 150 { 151 switch (m_op) { 152 case BooleanOperator::And: 153 if (m_right_truth) 154 return m_left->integer(); 155 return 0; 156 case BooleanOperator::Or: 157 if (m_left_truth) 158 return m_left->integer(); 159 return m_right->integer(); 160 } 161 VERIFY_NOT_REACHED(); 162 } 163 164 virtual DeprecatedString string() const override 165 { 166 switch (m_op) { 167 case BooleanOperator::And: 168 if (m_right_truth) 169 return m_left->string(); 170 return "0"; 171 case BooleanOperator::Or: 172 if (m_left_truth) 173 return m_left->string(); 174 return m_right->string(); 175 } 176 VERIFY_NOT_REACHED(); 177 } 178 virtual Type type() const override 179 { 180 switch (m_op) { 181 case BooleanOperator::And: 182 if (m_right_truth) 183 return m_left->type(); 184 return m_right->type(); 185 case BooleanOperator::Or: 186 if (m_left_truth) 187 return m_left->type(); 188 return m_right->type(); 189 } 190 VERIFY_NOT_REACHED(); 191 } 192 193 BooleanOperator m_op { BooleanOperator::And }; 194 NonnullOwnPtr<Expression> m_left, m_right; 195 bool m_left_truth { false }, m_right_truth { false }; 196}; 197 198class ComparisonExpression : public Expression { 199public: 200 enum class ComparisonOperation { 201 Less, 202 LessEq, 203 Eq, 204 Neq, 205 GreaterEq, 206 Greater, 207 }; 208 209 static ComparisonOperation op_from(StringView sv) 210 { 211 if (sv == "<"sv) 212 return ComparisonOperation::Less; 213 if (sv == "<="sv) 214 return ComparisonOperation::LessEq; 215 if (sv == "="sv) 216 return ComparisonOperation::Eq; 217 if (sv == "!="sv) 218 return ComparisonOperation::Neq; 219 if (sv == ">="sv) 220 return ComparisonOperation::GreaterEq; 221 return ComparisonOperation::Greater; 222 } 223 224 ComparisonExpression(ComparisonOperation op, NonnullOwnPtr<Expression>&& left, NonnullOwnPtr<Expression>&& right) 225 : m_op(op) 226 , m_left(move(left)) 227 , m_right(move(right)) 228 { 229 } 230 231private: 232 template<typename T> 233 bool compare(T const& left, T const& right) const 234 { 235 switch (m_op) { 236 case ComparisonOperation::Less: 237 return left < right; 238 case ComparisonOperation::LessEq: 239 return left == right || left < right; 240 case ComparisonOperation::Eq: 241 return left == right; 242 case ComparisonOperation::Neq: 243 return left != right; 244 case ComparisonOperation::GreaterEq: 245 return !(left < right); 246 case ComparisonOperation::Greater: 247 return left != right && !(left < right); 248 } 249 VERIFY_NOT_REACHED(); 250 } 251 252 virtual bool truth() const override 253 { 254 switch (m_left->type()) { 255 case Type::Integer: 256 return compare(m_left->integer(), m_right->integer()); 257 case Type::String: 258 return compare(m_left->string(), m_right->string()); 259 } 260 VERIFY_NOT_REACHED(); 261 } 262 virtual int integer() const override { return truth(); } 263 virtual DeprecatedString string() const override { return truth() ? "1" : "0"; } 264 virtual Type type() const override { return Type::Integer; } 265 266 ComparisonOperation m_op { ComparisonOperation::Less }; 267 NonnullOwnPtr<Expression> m_left, m_right; 268}; 269 270class ArithmeticExpression : public Expression { 271public: 272 enum class ArithmeticOperation { 273 Sum, 274 Difference, 275 Product, 276 Quotient, 277 Remainder, 278 }; 279 static ArithmeticOperation op_from(StringView sv) 280 { 281 if (sv == "+"sv) 282 return ArithmeticOperation::Sum; 283 if (sv == "-"sv) 284 return ArithmeticOperation::Difference; 285 if (sv == "*"sv) 286 return ArithmeticOperation::Product; 287 if (sv == "/"sv) 288 return ArithmeticOperation::Quotient; 289 return ArithmeticOperation::Remainder; 290 } 291 ArithmeticExpression(ArithmeticOperation op, NonnullOwnPtr<Expression>&& left, NonnullOwnPtr<Expression>&& right) 292 : m_op(op) 293 , m_left(move(left)) 294 , m_right(move(right)) 295 { 296 } 297 298private: 299 virtual bool truth() const override 300 { 301 switch (m_op) { 302 case ArithmeticOperation::Sum: 303 return m_left->truth() || m_right->truth(); 304 default: 305 return integer() != 0; 306 } 307 } 308 virtual int integer() const override 309 { 310 auto right = m_right->integer(); 311 if (right == 0) { 312 if (m_op == ArithmeticOperation::Product) 313 return 0; 314 if (m_op == ArithmeticOperation::Quotient || m_op == ArithmeticOperation::Remainder) 315 fail("Division by zero"); 316 } 317 318 auto left = m_left->integer(); 319 switch (m_op) { 320 case ArithmeticOperation::Product: 321 return right * left; 322 case ArithmeticOperation::Sum: 323 return right + left; 324 case ArithmeticOperation::Difference: 325 return left - right; 326 case ArithmeticOperation::Quotient: 327 return left / right; 328 case ArithmeticOperation::Remainder: 329 return left % right; 330 } 331 VERIFY_NOT_REACHED(); 332 } 333 virtual DeprecatedString string() const override 334 { 335 return DeprecatedString::formatted("{}", integer()); 336 } 337 virtual Type type() const override 338 { 339 return Type::Integer; 340 } 341 342 ArithmeticOperation m_op { ArithmeticOperation::Sum }; 343 NonnullOwnPtr<Expression> m_left, m_right; 344}; 345 346class StringExpression : public Expression { 347public: 348 enum class StringOperation { 349 Substring, 350 Index, 351 Length, 352 Match, 353 }; 354 355 StringExpression(StringOperation op, NonnullOwnPtr<Expression> string, OwnPtr<Expression> pos_or_chars = {}, OwnPtr<Expression> length = {}) 356 : m_op(op) 357 , m_str(move(string)) 358 , m_pos_or_chars(move(pos_or_chars)) 359 , m_length(move(length)) 360 { 361 } 362 363private: 364 virtual bool truth() const override 365 { 366 if (type() == Expression::Type::String) 367 return !string().is_empty(); 368 return integer() != 0; 369 } 370 virtual int integer() const override 371 { 372 if (m_op == StringOperation::Substring || m_op == StringOperation::Match) { 373 auto substr = string(); 374 if (auto integer = substr.to_int(); integer.has_value()) 375 return integer.value(); 376 else 377 fail("Not an integer: '{}'", substr); 378 } 379 380 if (m_op == StringOperation::Index) { 381 if (auto idx = m_str->string().find(m_pos_or_chars->string()); idx.has_value()) 382 return idx.value() + 1; 383 return 0; 384 } 385 386 if (m_op == StringOperation::Length) 387 return m_str->string().length(); 388 389 VERIFY_NOT_REACHED(); 390 } 391 static auto safe_substring(DeprecatedString const& str, int start, int length) 392 { 393 if (start < 1 || (size_t)start > str.length()) 394 fail("Index out of range"); 395 --start; 396 if (str.length() - start < (size_t)length) 397 fail("Index out of range"); 398 return str.substring(start, length); 399 } 400 virtual DeprecatedString string() const override 401 { 402 if (m_op == StringOperation::Substring) 403 return safe_substring(m_str->string(), m_pos_or_chars->integer(), m_length->integer()); 404 405 if (m_op == StringOperation::Match) { 406 auto match = m_compiled_regex->match(m_str->string(), PosixFlags::Global); 407 if (m_compiled_regex->parser_result.capture_groups_count == 0) { 408 if (!match.success) 409 return "0"; 410 411 size_t count = 0; 412 for (auto& m : match.matches) 413 count += m.view.length(); 414 415 return DeprecatedString::number(count); 416 } else { 417 if (!match.success) 418 return ""; 419 420 StringBuilder result; 421 for (auto& e : match.capture_group_matches[0]) 422 result.append(e.view.string_view()); 423 424 return result.to_deprecated_string(); 425 } 426 } 427 428 return DeprecatedString::number(integer()); 429 } 430 virtual Type type() const override 431 { 432 if (m_op == StringOperation::Substring) 433 return Type::String; 434 if (m_op == StringOperation::Match) { 435 if (!m_pos_or_chars) 436 fail("'match' expects a string pattern"); 437 438 ensure_regex(); 439 if (m_compiled_regex->parser_result.capture_groups_count == 0) 440 return Type::Integer; 441 442 return Type::String; 443 } 444 return Type::Integer; 445 } 446 447 void ensure_regex() const 448 { 449 if (!m_compiled_regex) { 450 m_compiled_regex = make<regex::Regex<PosixBasic>>(m_pos_or_chars->string()); 451 if (m_compiled_regex->parser_result.error != regex::Error::NoError) 452 fail("Regex error: {}", regex::get_error_string(m_compiled_regex->parser_result.error)); 453 } 454 } 455 456 StringOperation m_op { StringOperation::Substring }; 457 NonnullOwnPtr<Expression> m_str; 458 OwnPtr<Expression> m_pos_or_chars, m_length; 459 mutable OwnPtr<regex::Regex<PosixBasic>> m_compiled_regex; 460}; 461 462NonnullOwnPtr<Expression> Expression::parse(Queue<StringView>& args, Precedence prec) 463{ 464 switch (prec) { 465 case Or: { 466 auto left = parse(args, And); 467 while (!args.is_empty() && args.head() == "|") { 468 args.dequeue(); 469 auto right = parse(args, And); 470 left = make<BooleanExpression>(BooleanExpression::BooleanOperator::Or, move(left), move(right)); 471 } 472 return left; 473 } 474 case And: { 475 auto left = parse(args, Comp); 476 while (!args.is_empty() && args.head() == "&"sv) { 477 args.dequeue(); 478 auto right = parse(args, Comp); 479 left = make<BooleanExpression>(BooleanExpression::BooleanOperator::And, move(left), move(right)); 480 } 481 return left; 482 } 483 case Comp: { 484 auto left = parse(args, ArithS); 485 while (!args.is_empty() && args.head().is_one_of("<"sv, "<="sv, "="sv, "!="sv, "=>"sv, ">"sv)) { 486 auto op = args.dequeue(); 487 auto right = parse(args, ArithM); 488 left = make<ComparisonExpression>(ComparisonExpression::op_from(op), move(left), move(right)); 489 } 490 return left; 491 } 492 case ArithS: { 493 auto left = parse(args, ArithM); 494 while (!args.is_empty() && args.head().is_one_of("+"sv, "-"sv)) { 495 auto op = args.dequeue(); 496 auto right = parse(args, ArithM); 497 left = make<ArithmeticExpression>(ArithmeticExpression::op_from(op), move(left), move(right)); 498 } 499 return left; 500 } 501 case ArithM: { 502 auto left = parse(args, StringO); 503 while (!args.is_empty() && args.head().is_one_of("*"sv, "/"sv, "%"sv)) { 504 auto op = args.dequeue(); 505 auto right = parse(args, StringO); 506 left = make<ArithmeticExpression>(ArithmeticExpression::op_from(op), move(left), move(right)); 507 } 508 return left; 509 } 510 case StringO: { 511 if (args.is_empty()) 512 fail("Expected a term"); 513 514 OwnPtr<Expression> left; 515 516 while (!args.is_empty()) { 517 auto& op = args.head(); 518 if (op == "+"sv) { 519 args.dequeue(); 520 left = make<ValueExpression>(args.dequeue()); 521 } else if (op == "substr"sv) { 522 args.dequeue(); 523 auto str = parse(args, Paren); 524 auto pos = parse(args, Paren); 525 auto len = parse(args, Paren); 526 left = make<StringExpression>(StringExpression::StringOperation::Substring, move(str), move(pos), move(len)); 527 } else if (op == "index"sv) { 528 args.dequeue(); 529 auto str = parse(args, Paren); 530 auto chars = parse(args, Paren); 531 left = make<StringExpression>(StringExpression::StringOperation::Index, move(str), move(chars)); 532 } else if (op == "match"sv) { 533 args.dequeue(); 534 auto str = parse(args, Paren); 535 auto pattern = parse(args, Paren); 536 left = make<StringExpression>(StringExpression::StringOperation::Match, move(str), move(pattern)); 537 } else if (op == "length"sv) { 538 args.dequeue(); 539 auto str = parse(args, Paren); 540 left = make<StringExpression>(StringExpression::StringOperation::Length, move(str)); 541 } else if (!left) { 542 left = parse(args, Paren); 543 } 544 545 if (!args.is_empty() && args.head() == ":"sv) { 546 args.dequeue(); 547 auto right = parse(args, Paren); 548 left = make<StringExpression>(StringExpression::StringOperation::Match, left.release_nonnull(), move(right)); 549 } else { 550 return left.release_nonnull(); 551 } 552 } 553 554 return left.release_nonnull(); 555 } 556 case Paren: { 557 if (args.is_empty()) 558 fail("Expected a term"); 559 560 if (args.head() == "("sv) { 561 args.dequeue(); 562 auto expr = parse(args); 563 if (args.head() != ")") 564 fail("Expected a close paren"); 565 args.dequeue(); 566 return expr; 567 } 568 569 return make<ValueExpression>(args.dequeue()); 570 } 571 } 572 573 fail("Invalid expression"); 574} 575 576ErrorOr<int> serenity_main(Main::Arguments arguments) 577{ 578 TRY(Core::System::pledge("stdio"sv)); 579 TRY(Core::System::unveil(nullptr, nullptr)); 580 581 if ((arguments.strings.size() == 2 && "--help"sv == arguments.strings[1]) || arguments.strings.size() == 1) 582 print_help_and_exit(); 583 584 Queue<StringView> args; 585 for (size_t i = 1; i < arguments.strings.size(); ++i) 586 args.enqueue(arguments.strings[i]); 587 588 auto expression = Expression::parse(args); 589 if (!args.is_empty()) 590 fail("Extra tokens at the end of the expression"); 591 592 switch (expression->type()) { 593 case Expression::Type::Integer: 594 outln("{}", expression->integer()); 595 break; 596 case Expression::Type::String: 597 outln("{}", expression->string()); 598 break; 599 } 600 return expression->truth() ? 0 : 1; 601}