├── CMakeLists.txt ├── LICENSE ├── README.md ├── build └── .gitignore ├── src ├── context.cpp ├── context.h ├── exceptions.h ├── grammar.cpp ├── grammar.h ├── instance.cpp ├── instance.h ├── knuckleball.cpp ├── parser.cpp ├── parser.h ├── server.cpp ├── server.h ├── str_utils.cpp └── str_utils.h └── tests ├── context_test.cpp ├── grammar_test.cpp ├── instance_test.cpp ├── parser_test.cpp └── str_utils_test.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016, Rodrigo Alves Lima 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 5 | # following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 8 | # following disclaimer. 9 | # 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 11 | # following disclaimer in the documentation and/or other materials provided with the distribution. 12 | # 13 | # 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 14 | # derived from this software without specific prior written permission. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 | # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | cmake_minimum_required(VERSION 2.8) 25 | 26 | project(knuckleball) 27 | 28 | # Dependencies 29 | find_package(GTest QUIET) 30 | find_package(Boost 1.58 COMPONENTS system program_options REQUIRED) 31 | 32 | # Compiler options 33 | set(EXECUTABLE_OUTPUT_PATH "build") 34 | set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -std=c++11 -pthread") 35 | include_directories(src) 36 | include_directories(${Boost_INCLUDE_DIRS}) 37 | link_directories(${Boost_LIBRARY_DIRS}) 38 | 39 | # List files 40 | set(HEADERS src/context.h src/exceptions.h src/grammar.h src/instance.h src/parser.h src/server.h src/str_utils.h) 41 | set(SOURCES src/context.cpp src/grammar.cpp src/instance.cpp src/parser.cpp src/server.cpp src/str_utils.cpp) 42 | set(UNIT_TESTS tests/context_test.cpp tests/grammar_test.cpp tests/instance_test.cpp tests/parser_test.cpp 43 | tests/str_utils_test.cpp) 44 | 45 | # Unit tests 46 | if (GTEST_FOUND) 47 | enable_testing() 48 | include_directories(${GTEST_INCLUDE_DIRS}) 49 | add_executable(unit_tests ${UNIT_TESTS} ${HEADERS} ${SOURCES}) 50 | target_link_libraries(unit_tests ${GTEST_BOTH_LIBRARIES} ${Boost_LIBRARIES}) 51 | GTEST_ADD_TESTS(unit_tests "" ${UNIT_TESTS}) 52 | endif (GTEST_FOUND) 53 | 54 | # Build 55 | add_executable(knuckleball src/knuckleball.cpp ${HEADERS} ${SOURCES}) 56 | target_link_libraries(knuckleball ${Boost_LIBRARIES}) 57 | install(TARGETS knuckleball DESTINATION build) 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Rodrigo Alves Lima 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 5 | following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 8 | following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 11 | following disclaimer in the documentation and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Knuckleball 2 | Knuckleball is an in-memory data structure server. It provides a language with a syntax similar to that of Smalltalk to create and manipulate simple data types like booleans, characters, integers, floats and strings, and containers like vectors, sets and dictionaries. Knuckleball is implemented as a single-threaded and asynchronous server, so it can handle multiple incoming connections and concurrency is not an issue. It can be used as cache or message broker. Usage as database is not advised by now since data is not being persisted on disk yet. 3 | 4 | **Table of Contents** 5 | * [Building](#building) 6 | * [Dependencies](#dependencies) 7 | * [Compiling](#compiling) 8 | * [Testing](#testing) 9 | * [Getting Started](#getting-started) 10 | * [Reference](#reference) 11 | * [Boolean](#boolean) 12 | * [Character](#character) 13 | * [Integer](#integer) 14 | * [Float](#float) 15 | * [String](#string) 16 | * [Vector](#vector) 17 | * [Set](#set) 18 | * [Dictionary](#dictionary) 19 | * [Future work](#future-work) 20 | 21 | ## Building 22 | Knuckleball is being tested on Linux and OS X. It may be compiled on other systems, perhaps with minor modifications. 23 | 24 | ### Dependencies 25 | * [Boost](http://www.boost.org/) >= 1.58: on Ubuntu you should install the package `libboost-all-dev`, and on OS X you should install the port `boost`. 26 | * [Google Test](https://github.com/google/googletest) >= 1.7.0: this framework is only used for testing, so it is not required. On Ubuntu you should install the package `libgtest-dev` and follow these [steps](http://www.eriksmistad.no/getting-started-with-google-test-on-ubuntu/), and on OS X you should install the port `gtest`. 27 | 28 | ### Compiling 29 | ``` 30 | $ cmake CMakeLists.txt 31 | $ make 32 | ``` 33 | 34 | ### Testing 35 | ``` 36 | $ make test 37 | ``` 38 | 39 | ## Getting started 40 | To run the server on port 8001 of localhost, type: 41 | ``` 42 | $ cd build 43 | $ ./knuckleball --bind 127.0.0.1 --port 8001 44 | ``` 45 | 46 | To list all the options available, type: 47 | ``` 48 | $ ./knuckleball --help 49 | ``` 50 | 51 | You can use `telnet` to play with Knuckleball. A Python [client](https://github.com/ral99/knuckleball-py) is also available. 52 | 53 | The following example shows how to instantiate and manipulate an integer: 54 | ``` 55 | $ telnet 127.0.0.1 8001 56 | Integer create: i withValue: 42; 57 | > null 58 | i add: 8; 59 | > null 60 | i get; 61 | > 50 62 | ``` 63 | 64 | The following example shows how to instantiate and manipulate a vector of integers declared inside a namespace called `mynamespace`: 65 | ``` 66 | $ telnet 127.0.0.1 8001 67 | Vector create: mynamespace::points; 68 | > null 69 | mynamespace::points pushBack: 3; 70 | > null 71 | mynamespace::points pushBack: 7; 72 | > null 73 | mynamespace::points pushBack: 5; 74 | > null 75 | mynamespace::points popFront; 76 | > 3 77 | mynamespace::points get; 78 | > [7,5] 79 | ``` 80 | 81 | The following example shows how to instantiate and manipulate a set of strings: 82 | ``` 83 | $ telnet 127.0.0.1 8001 84 | Set create: players; 85 | > null 86 | players add: "Babe Ruth"; 87 | > null 88 | players add: "David Ortiz"; 89 | > null 90 | players add: "Paulo Orlando"; 91 | > null 92 | players contains? "Jake Arrieta"; 93 | > false 94 | players get; 95 | > {"Babe Ruth","David Ortiz","Paulo Orlando"} 96 | ``` 97 | 98 | The following example shows how to instantiate and manipulate a dictionary that associates floats with strings: 99 | ``` 100 | $ telnet 127.0.0.1 8001 101 | Dictionary create: ERAs; 102 | > null 103 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 104 | > null 105 | ERAs associateValue: 2.21 withKey: "Mariano Rivera"; 106 | > null 107 | ERAs associateValue: 2.39 withKey: "Clayton Kershaw"; 108 | > null 109 | ERAs getValueForKey: "Mariano Rivera"; 110 | > 2.210 111 | ERAs get; 112 | > (("Clayton Kershaw",2.390),("Ed Walsh",1.820),("Mariano Rivera",2.210)) 113 | ``` 114 | 115 | ## Reference 116 | Types are divided into: 117 | * **Objects**: [Booleans](#boolean), [Characters](#character), [Integers](#integer), [Floats](#float) and [Strings](#string). 118 | * **Containers**: strongly typed [Vectors](#vector), [Sets](#set) and [Dictionaries](#dictionaryare) of **Objects**. 119 | 120 | ### Boolean 121 | Booleans are objects that can only represent one of two states: `true` or `false`. 122 | 123 | #### Constructors: 124 | * **create: (variable) withValue: (boolean)** 125 | - Returns: null 126 | ``` 127 | Boolean create: t withValue: true; 128 | > null 129 | Boolean create: f withValue: false; 130 | > null 131 | t get; 132 | > true 133 | f get; 134 | > false 135 | ``` 136 | 137 | * **createIfNotExists: (variable) withValue: (boolean)** 138 | - Returns: null 139 | ``` 140 | Boolean createIfNotExists: t withValue: true; 141 | > null 142 | Boolean createIfNotExists: f withValue: false; 143 | > null 144 | t get; 145 | > true 146 | f get; 147 | > false 148 | ``` 149 | 150 | #### Methods: 151 | * **get** 152 | - Returns: boolean 153 | ``` 154 | Boolean create: t withValue: true; 155 | > null 156 | t get; 157 | > true 158 | ``` 159 | 160 | * **set: (boolean)** 161 | - Returns: null 162 | ``` 163 | Boolean create: t withValue: true; 164 | > null 165 | t set: false; 166 | > null 167 | t get; 168 | > false 169 | ``` 170 | 171 | * **isTrue?** 172 | - Returns: boolean 173 | ``` 174 | Boolean create: t withValue: true; 175 | > null 176 | Boolean create: f withValue: false; 177 | > null 178 | t isTrue?; 179 | > true 180 | f isTrue?; 181 | > false 182 | ``` 183 | 184 | * **isFalse?** 185 | - Returns: boolean 186 | ``` 187 | Boolean create: t withValue: true; 188 | > null 189 | Boolean create: f withValue: false; 190 | > null 191 | t isFalse?; 192 | > false 193 | f isFalse?; 194 | > true 195 | ``` 196 | 197 | ### Character 198 | Characters are objects that can represent a single character, such as `'a'` or `'0'`. 199 | 200 | #### Constructors: 201 | * **create: (variable) withValue: (character)** 202 | - Returns: null 203 | ``` 204 | Character create: alphabetic withValue: 'a'; 205 | > null 206 | Character create: numeric withValue: '0'; 207 | > null 208 | Character create: space withValue: ' '; 209 | > null 210 | alphabetic get; 211 | > 'a' 212 | numeric get; 213 | > '0' 214 | space get; 215 | > ' ' 216 | ``` 217 | 218 | * **createIfNotExists: (variable) withValue: (character)** 219 | - Returns: null 220 | ``` 221 | Character createIfNotExists: alphabetic withValue: 'a'; 222 | > null 223 | Character createIfNotExists: numeric withValue: '0'; 224 | > null 225 | Character createIfNotExists: space withValue: ' '; 226 | > null 227 | alphabetic get; 228 | > 'a' 229 | numeric get; 230 | > '0' 231 | space get; 232 | > ' ' 233 | ``` 234 | 235 | #### Methods: 236 | * **get** 237 | - Returns: character 238 | ``` 239 | Character create: alphabetic withValue: 'a'; 240 | > null 241 | alphabetic get; 242 | > 'a' 243 | ``` 244 | 245 | * **set: (character)** 246 | - Returns: null 247 | ``` 248 | Character create: alphabetic withValue: 'a'; 249 | > null 250 | alphabetic set: 'z'; 251 | > null 252 | alphabetic get; 253 | > 'z' 254 | ``` 255 | 256 | * **isAlphabetic?** 257 | - Returns: boolean 258 | ``` 259 | Character create: alphabetic withValue: 'a'; 260 | > null 261 | Character create: numeric withValue: '0'; 262 | > null 263 | Character create: space withValue: ' '; 264 | > null 265 | alphabetic isAlphabetic?; 266 | > true 267 | numeric isAlphabetic?; 268 | > false 269 | space isAlphabetic?; 270 | > false 271 | ``` 272 | 273 | * **isNumeric?** 274 | - Returns: boolean 275 | ``` 276 | Character create: alphabetic withValue: 'a'; 277 | > null 278 | Character create: numeric withValue: '0'; 279 | > null 280 | Character create: space withValue: ' '; 281 | > null 282 | alphabetic isNumeric?; 283 | > false 284 | numeric isNumeric?; 285 | > true 286 | space isNumeric?; 287 | > false 288 | ``` 289 | 290 | * **isAlphanumeric?** 291 | - Returns: boolean 292 | ``` 293 | Character create: alphabetic withValue: 'a'; 294 | > null 295 | Character create: numeric withValue: '0'; 296 | > null 297 | Character create: space withValue: ' '; 298 | > null 299 | alphabetic isAlphanumeric?; 300 | > true 301 | numeric isAlphanumeric?; 302 | > true 303 | space isAlphanumeric?; 304 | > false 305 | ``` 306 | 307 | * **isSpace?** 308 | - Returns: boolean 309 | ``` 310 | Character create: alphabetic withValue: 'a'; 311 | > null 312 | Character create: numeric withValue: '0'; 313 | > null 314 | Character create: space withValue: ' '; 315 | > null 316 | alphabetic isSpace?; 317 | > false 318 | numeric isSpace?; 319 | > false 320 | space isSpace?; 321 | > true 322 | ``` 323 | 324 | * **isEqualTo? (character)** 325 | - Returns: boolean 326 | ``` 327 | Character create: alphabetic withValue: 'a'; 328 | > null 329 | alphabetic isEqualTo? 'a'; 330 | > true 331 | alphabetic isEqualTo? 'z'; 332 | > false 333 | ``` 334 | 335 | * **isLessThan? (character)** 336 | - Returns: boolean 337 | ``` 338 | Character create: alphabetic withValue: 'a'; 339 | > null 340 | alphabetic isLessThan? 'z'; 341 | > true 342 | alphabetic isLessThan? 'a'; 343 | > false 344 | ``` 345 | 346 | * **isLessThanOrEqualTo? (character)** 347 | - Returns: boolean 348 | ``` 349 | Character create: alphabetic withValue: 'z'; 350 | > null 351 | alphabetic isLessThanOrEqualTo? 'z'; 352 | > true 353 | alphabetic isLessThanOrEqualTo? 'a'; 354 | > false 355 | ``` 356 | 357 | * **isGreaterThan? (character)** 358 | - Returns: boolean 359 | ``` 360 | Character create: alphabetic withValue: 'z'; 361 | > null 362 | alphabetic isGreaterThan? 'a'; 363 | > true 364 | alphabetic isGreaterThan? 'z'; 365 | > false 366 | ``` 367 | 368 | * **isGreaterThanOrEqualTo? (character)** 369 | - Returns: boolean 370 | ``` 371 | Character create: alphabetic withValue: 'a'; 372 | > null 373 | alphabetic isGreaterThanOrEqualTo? 'a'; 374 | > true 375 | alphabetic isGreaterThanOrEqualTo? 'z'; 376 | > false 377 | ``` 378 | 379 | ### Integer 380 | Integers are objects that can represent a whole number value, such as `42` or `-42`. Floating-point values, such as `42.5`, can be casted to integers. 381 | 382 | #### Constructors: 383 | * **create: (variable) withValue: (integer)** 384 | - Returns: null 385 | ``` 386 | Integer create: i withValue: 42; 387 | > null 388 | i get; 389 | > 42 390 | ``` 391 | 392 | * **createIfNotExists: (variable) withValue: (integer)** 393 | - Returns: null 394 | ``` 395 | Integer createIfNotExists: i withValue: 42; 396 | > null 397 | i get; 398 | > 42 399 | ``` 400 | 401 | #### Methods: 402 | * **get** 403 | - Returns: integer 404 | ``` 405 | Integer create: i withValue: 42; 406 | > null 407 | i get; 408 | > 42 409 | ``` 410 | 411 | * **set: (integer)** 412 | - Returns: null 413 | ``` 414 | Integer create: i withValue: 42; 415 | > null 416 | i set: -42; 417 | > null 418 | i get; 419 | > -42 420 | ``` 421 | 422 | * **isEqualTo? (integer)** 423 | - Returns: boolean 424 | ``` 425 | Integer create: i withValue: 42; 426 | > null 427 | i isEqualTo? 42; 428 | > true 429 | i isEqualTo? 0; 430 | > false 431 | ``` 432 | 433 | * **isLessThan? (integer)** 434 | - Returns: boolean 435 | ``` 436 | Integer create: i withValue: 0; 437 | > null 438 | i isLessThan? 42; 439 | > true 440 | i isLessThan? 0; 441 | > false 442 | ``` 443 | 444 | * **isLessThanOrEqualTo? (integer)** 445 | - Returns: boolean 446 | ``` 447 | Integer create: i withValue: 42; 448 | > null 449 | i isLessThanOrEqualTo? 42; 450 | > true 451 | i isLessThanOrEqualTo? 0; 452 | > false 453 | ``` 454 | 455 | * **isGreaterThan? (integer)** 456 | - Returns: boolean 457 | ``` 458 | Integer create: i withValue: 42; 459 | > null 460 | i isGreaterThan? 0; 461 | > true 462 | i isGreaterThan? 42; 463 | > false 464 | ``` 465 | 466 | * **isGreaterThanOrEqualTo? (integer)** 467 | - Returns: boolean 468 | ``` 469 | Integer create: i withValue: 0; 470 | > null 471 | i isGreaterThanOrEqualTo? 0; 472 | > true 473 | i isGreaterThanOrEqualTo? 42; 474 | > false 475 | ``` 476 | 477 | * **add: (integer)** 478 | - Returns: null 479 | ``` 480 | Integer create: i withValue: 42; 481 | > null 482 | i add: 10; 483 | > null 484 | i get; 485 | > 52 486 | ``` 487 | 488 | * **subtract: (integer)** 489 | - Returns: null 490 | ``` 491 | Integer create: i withValue: 52; 492 | > null 493 | i subtract: 10; 494 | > null 495 | i get; 496 | > 42 497 | ``` 498 | 499 | * **multiplyBy: (float)** 500 | - Returns: null 501 | ``` 502 | Integer create: i withValue: 10; 503 | > null 504 | i multiplyBy: 4.2; 505 | > null 506 | i get; 507 | > 42 508 | ``` 509 | 510 | * **divideBy: (float)** 511 | - Returns: null 512 | ``` 513 | Integer create: i withValue: 42; 514 | > null 515 | i divideBy: 4.2; 516 | > null 517 | i get; 518 | > 10 519 | ``` 520 | 521 | ### Float 522 | Floats are objects that can represent a real value, such as `3.1415` or `1e-3`. 523 | 524 | #### Constructors: 525 | * **create: (variable) withValue: (float)** 526 | - Returns: null 527 | ``` 528 | Float create: f withValue: 42.0; 529 | > null 530 | Float create: e withValue: 1e-2; 531 | > null 532 | f get; 533 | > 42.000 534 | e get; 535 | > 0.010 536 | ``` 537 | 538 | * **createIfNotExists: (variable) withValue: (float)** 539 | - Returns: null 540 | ``` 541 | Float createIfNotExists: f withValue: 42.0; 542 | > null 543 | Float createIfNotExists: e withValue: 1e-2; 544 | > null 545 | f get; 546 | > 42.000 547 | e get; 548 | > 0.010 549 | ``` 550 | 551 | #### Methods: 552 | * **get** 553 | - Returns: float 554 | ``` 555 | Float create: f withValue: 42.0; 556 | > null 557 | f get; 558 | > 42.000 559 | ``` 560 | 561 | * **set: (float)** 562 | - Returns: null 563 | ``` 564 | Float create: f withValue: 42.0; 565 | > null 566 | f set: -42.0; 567 | > null 568 | f get; 569 | > -42.000 570 | ``` 571 | 572 | * **isEqualTo? (float)** 573 | - Returns: boolean 574 | ``` 575 | Float create: f withValue: 42.0; 576 | > null 577 | f isEqualTo? 42.0; 578 | > true 579 | f isEqualTo? 0.0; 580 | > false 581 | ``` 582 | 583 | * **isLessThan? (float)** 584 | - Returns: boolean 585 | ``` 586 | Float create: f withValue: 0.0; 587 | > null 588 | f isLessThan? 42.0; 589 | > true 590 | f isLessThan? 0.0; 591 | > false 592 | ``` 593 | 594 | * **isLessThanOrEqualTo? (float)** 595 | - Returns: boolean 596 | ``` 597 | Float create: f withValue: 42.0; 598 | > null 599 | f isLessThanOrEqualTo? 42.0; 600 | > true 601 | f isLessThanOrEqualTo? 0.0; 602 | > false 603 | ``` 604 | 605 | * **isGreaterThan? (float)** 606 | - Returns: boolean 607 | ``` 608 | Float create: f withValue: 42.0; 609 | > null 610 | f isGreaterThan? 0.0; 611 | > true 612 | f isGreaterThan? 42.0; 613 | > false 614 | ``` 615 | 616 | * **isGreaterThanOrEqualTo? (float)** 617 | - Returns: boolean 618 | ``` 619 | Float create: f withValue: 0.0; 620 | > null 621 | f isGreaterThanOrEqualTo? 0.0; 622 | > true 623 | f isGreaterThanOrEqualTo? 42.0; 624 | > false 625 | ``` 626 | 627 | * **add: (float)** 628 | - Returns: null 629 | ``` 630 | Float create: f withValue: 42.0; 631 | > null 632 | f add: 10.0; 633 | > null 634 | f get; 635 | > 52.000 636 | ``` 637 | 638 | * **subtract: (float)** 639 | - Returns: null 640 | ``` 641 | Float create: f withValue: 52.0; 642 | > null 643 | f subtract: 10.0; 644 | > null 645 | f get; 646 | > 42.000 647 | ``` 648 | 649 | * **multiplyBy: (float)** 650 | - Returns: null 651 | ``` 652 | Float create: f withValue: 4.2; 653 | > null 654 | f multiplyBy: 10.0; 655 | > null 656 | f get; 657 | 42.000; 658 | ``` 659 | 660 | * **divideBy: (float)** 661 | - Returns: null 662 | ``` 663 | Float create: f withValue: 42.0; 664 | > null 665 | f divideBy: 4.2; 666 | > null 667 | f get; 668 | > 10.000 669 | ``` 670 | 671 | ### String 672 | Strings are objects that can represent a sequence of characters, such as `"knuckleball"`. 673 | 674 | #### Constructors: 675 | * **create: (variable)** 676 | - Returns: null 677 | ``` 678 | String create: str; 679 | > null 680 | str get; 681 | > "" 682 | ``` 683 | 684 | * **createIfNotExists: (variable)** 685 | - Returns: null 686 | ``` 687 | String createIfNotExists: str; 688 | > null 689 | str get; 690 | > "" 691 | ``` 692 | 693 | * **create: (variable) withValue: (string)** 694 | - Returns: null 695 | ``` 696 | String create: str withValue: "knuckleball"; 697 | > null 698 | str get; 699 | > "knuckleball" 700 | ``` 701 | 702 | * **createIfNotExists: (variable) withValue: (string)** 703 | - Returns: null 704 | ``` 705 | String createIfNotExists: str withValue: "knuckleball"; 706 | > null 707 | str get; 708 | > "knuckleball" 709 | ``` 710 | 711 | #### Methods: 712 | * **get** 713 | - Returns: string 714 | ``` 715 | String create: str withValue: "knuckleball"; 716 | > null 717 | str get; 718 | > "knuckleball" 719 | ``` 720 | 721 | * **set: (string)** 722 | - Returns: null 723 | ``` 724 | String create: str withValue: ""; 725 | > null 726 | str set: "knuckleball"; 727 | > null 728 | str get; 729 | > "knuckleball" 730 | ``` 731 | 732 | * **isEmpty?** 733 | - Returns: boolean 734 | ``` 735 | String create: str withValue: ""; 736 | > null 737 | str isEmpty?; 738 | > true 739 | str concatenate: "knuckleball"; 740 | > null 741 | str isEmpty?; 742 | > false 743 | ``` 744 | 745 | * **startsWith? (string)** 746 | - Returns: boolean 747 | ``` 748 | String create: str withValue: "knuckleball"; 749 | > null 750 | str startsWith? "knuckle"; 751 | > true 752 | str startsWith? "ball"; 753 | > false 754 | ``` 755 | 756 | * **endsWith? (string)** 757 | - Returns: boolean 758 | ``` 759 | String create: str withValue: "knuckleball"; 760 | > null 761 | str endsWith? "ball"; 762 | > true 763 | str endsWith? "knuckle"; 764 | > false 765 | ``` 766 | 767 | * **isLexicographicallyEqualTo? (string)** 768 | - Returns: boolean 769 | ``` 770 | String create: str withValue: "knuckleball"; 771 | > null 772 | str isLexicographicallyEqualTo? "knuckleball"; 773 | > true 774 | str isLexicographicallyEqualTo? ""; 775 | > false 776 | ``` 777 | 778 | * **isLexicographicallyLessThan? (string)** 779 | - Returns: boolean 780 | ``` 781 | String create: str withValue: ""; 782 | > null 783 | str isLexicographicallyLessThan? "knuckleball"; 784 | > true 785 | str isLexicographicallyLessThan? ""; 786 | > false 787 | ``` 788 | 789 | * **isLexicographicallyLessThanOrEqualTo? (string)** 790 | - Returns: boolean 791 | ``` 792 | String create: str withValue: "knuckleball"; 793 | > null 794 | str isLexicographicallyLessThanOrEqualTo? "knuckleball"; 795 | > true 796 | str isLexicographicallyLessThanOrEqualTo? ""; 797 | > false 798 | ``` 799 | 800 | * **isLexicographicallyGreaterThan? (string)** 801 | - Returns: boolean 802 | ``` 803 | String create: str withValue: "knuckleball"; 804 | > null 805 | str isLexicographicallyGreaterThan? ""; 806 | > true 807 | str isLexicographicallyGreaterThan? "knuckleball"; 808 | > false 809 | ``` 810 | 811 | * **isLexicographicallyGreaterThanOrEqualTo? (string)** 812 | - Returns: boolean 813 | ``` 814 | String create: str withValue: ""; 815 | > null 816 | str isLexicographicallyGreaterThanOrEqualTo? ""; 817 | > true 818 | str isLexicographicallyGreaterThanOrEqualTo? "knuckleball"; 819 | > false 820 | ``` 821 | 822 | * **length** 823 | - Returns: integer 824 | ``` 825 | String create: str withValue: "knuckleball"; 826 | > null 827 | str length; 828 | > 11 829 | ``` 830 | 831 | * **atIndex: (integer)** 832 | - Returns: character 833 | ``` 834 | String create: str withValue: "knuckleball"; 835 | > null 836 | str atIndex: 0; 837 | > 'k' 838 | ``` 839 | 840 | * **first: (integer)** 841 | - Returns: string 842 | ``` 843 | String create: str withValue: "knuckleball"; 844 | > null 845 | str first: 7; 846 | > "knuckle" 847 | ``` 848 | 849 | * **last: (integer)** 850 | - Returns: string 851 | ``` 852 | String create: str withValue: "knuckleball"; 853 | > null 854 | str last: 4; 855 | > "ball" 856 | ``` 857 | 858 | * **substringFromIndex: (integer)** 859 | - Returns: string 860 | ``` 861 | String create: str withValue: "knuckleball"; 862 | > null 863 | str substringFromIndex: 7; 864 | > "ball" 865 | ``` 866 | 867 | * **substringFromIndex: (integer) toIndex: (integer)** 868 | - Returns: string 869 | ``` 870 | String create: str withValue: "knuckleball"; 871 | > null 872 | str substringFromIndex: 0 toIndex: 7; 873 | > "knuckle" 874 | ``` 875 | 876 | * **pushBack: (character)** 877 | - Returns: null 878 | ``` 879 | String create: str withValue: "knucklebal"; 880 | > null 881 | str pushBack: 'l'; 882 | > null 883 | str get; 884 | > "knuckleball" 885 | ``` 886 | 887 | * **pushFront: (character)** 888 | - Returns: null 889 | ``` 890 | String create: str withValue: "nuckleball"; 891 | > null 892 | str pushFront: 'k'; 893 | > null 894 | str get; 895 | > "knuckleball" 896 | ``` 897 | 898 | * **popBack** 899 | - Returns: character 900 | ``` 901 | String create: str withValue: "knuckleball"; 902 | > null 903 | str popBack; 904 | > 'l' 905 | str get; 906 | > "knucklebal" 907 | ``` 908 | 909 | * **popFront** 910 | - Returns: character 911 | ``` 912 | String create: str withValue: "knuckleball"; 913 | > null 914 | str popFront; 915 | > 'k' 916 | str get; 917 | > "nuckleball" 918 | ``` 919 | 920 | * **popAtIndex: (integer)** 921 | - Returns: character 922 | ``` 923 | String create: str withValue: "knuckleball"; 924 | > null 925 | str popAtIndex: 2; 926 | > 'u' 927 | str get; 928 | > "knckleball" 929 | ``` 930 | 931 | * **concatenate: (string)** 932 | - Returns: null 933 | ``` 934 | String create: str withValue: "knuckle"; 935 | > null 936 | str concatenate: "ball"; 937 | > null 938 | str get; 939 | > "knuckleball" 940 | ``` 941 | 942 | * **insert: (string) beforeIndex: (integer)** 943 | - Returns: null 944 | ``` 945 | String create: str withValue: "knkleball"; 946 | > null 947 | str insert: "uc" beforeIndex: 2; 948 | > null 949 | str get; 950 | > "knuckleball" 951 | ``` 952 | 953 | * **eraseFromIndex: (integer)** 954 | - Returns: null 955 | ``` 956 | String create: str withValue: "knuckleball"; 957 | > null 958 | str eraseFromIndex: 7; 959 | > null 960 | str get; 961 | > "knuckle" 962 | ``` 963 | 964 | * **eraseFromIndex: (integer) toIndex: (integer)** 965 | - Returns: null 966 | ``` 967 | String create: str withValue: "knuckleball"; 968 | > null 969 | str eraseFromIndex: 7 toIndex: 9; 970 | > null 971 | str get; 972 | > "knucklell" 973 | ``` 974 | 975 | * **clear** 976 | - Returns: null 977 | ``` 978 | String create: str withValue: "knuckleball"; 979 | > null 980 | str clear; 981 | > null 982 | str get; 983 | > "" 984 | ``` 985 | 986 | ### Vector 987 | Vectors are containers that store elements using contiguous storage locations. 988 | 989 | #### Constructors: 990 | * **create: (variable)** 991 | - Returns: null 992 | ``` 993 | Vector create: points; 994 | > null 995 | points get; 996 | > [] 997 | ``` 998 | 999 | * **createIfNotExists: (variable)** 1000 | - Returns: null 1001 | ``` 1002 | Vector createIfNotExists: points; 1003 | > null 1004 | points get; 1005 | > [] 1006 | ``` 1007 | 1008 | #### Methods: 1009 | * **get** 1010 | - Returns: vector 1011 | ``` 1012 | Vector create: points; 1013 | > null 1014 | points get; 1015 | > [] 1016 | ``` 1017 | 1018 | * **isEmpty?** 1019 | - Returns: boolean 1020 | ``` 1021 | Vector create: points; 1022 | > null 1023 | points isEmpty?; 1024 | > true 1025 | points pushBack: 42; 1026 | > null 1027 | points isEmpty?; 1028 | > false 1029 | ``` 1030 | 1031 | * **contains? (object)** 1032 | - Returns: boolean 1033 | ``` 1034 | Vector create: points; 1035 | > null 1036 | points contains? 42; 1037 | > false 1038 | points pushBack: 42; 1039 | > null 1040 | points contains? 42; 1041 | > true 1042 | ``` 1043 | 1044 | * **contains? (object) fromIndex: (integer)** 1045 | - Returns: boolean 1046 | ``` 1047 | Vector create: points; 1048 | > null 1049 | points pushBack: 3; 1050 | > null 1051 | points pushBack: 7; 1052 | > null 1053 | points pushBack: 5; 1054 | > null 1055 | points contains? 7 fromIndex: 0; 1056 | > true 1057 | points contains? 7 fromIndex: 2; 1058 | > false 1059 | ``` 1060 | 1061 | * **count: (object)** 1062 | - Returns: integer 1063 | ``` 1064 | Vector create: points; 1065 | > null 1066 | points pushBack: 3; 1067 | > null 1068 | points pushBack: 7; 1069 | > null 1070 | points pushBack: 7; 1071 | > null 1072 | points count: 7; 1073 | > 2 1074 | ``` 1075 | 1076 | * **atIndex: (integer)** 1077 | - Returns: object 1078 | ``` 1079 | Vector create: points; 1080 | > null 1081 | points pushBack: 3; 1082 | > null 1083 | points pushBack: 5; 1084 | > null 1085 | points pushBack: 7; 1086 | > null 1087 | points atIndex: 0; 1088 | > 3 1089 | ``` 1090 | 1091 | * **firstIndexOf: (object)** 1092 | - Returns: integer 1093 | ``` 1094 | Vector create: points; 1095 | > null 1096 | points pushBack: 3; 1097 | > null 1098 | points pushBack: 5; 1099 | > null 1100 | points pushBack: 3; 1101 | > null 1102 | points pushBack: 5; 1103 | > null 1104 | points firstIndexOf: 5; 1105 | > 1 1106 | ``` 1107 | 1108 | * **firstIndexOf: (object) fromIndex: (integer)** 1109 | - Returns: integer 1110 | ``` 1111 | Vector create: points; 1112 | > null 1113 | points pushBack: 3; 1114 | > null 1115 | points pushBack: 5; 1116 | > null 1117 | points pushBack: 3; 1118 | > null 1119 | points pushBack: 5; 1120 | > null 1121 | points firstIndexOf: 3 fromIndex: 1; 1122 | > 2 1123 | ``` 1124 | 1125 | * **allIndexesOf: (object)** 1126 | - Returns: vector 1127 | ``` 1128 | Vector create: points; 1129 | > null 1130 | points pushBack: 3; 1131 | > null 1132 | points pushBack: 5; 1133 | > null 1134 | points pushBack: 3; 1135 | > null 1136 | points allIndexesOf: 3; 1137 | > [0,2] 1138 | ``` 1139 | 1140 | * **size** 1141 | - Returns: Integer 1142 | ``` 1143 | Vector create: points; 1144 | > null 1145 | points pushBack: 3; 1146 | > null 1147 | points pushBack: 5; 1148 | > null 1149 | points pushBack: 7; 1150 | > null 1151 | points size; 1152 | > 3 1153 | ``` 1154 | 1155 | * **first: (integer)** 1156 | - Returns: vector 1157 | ``` 1158 | Vector create: points; 1159 | > null 1160 | points pushBack: 3; 1161 | > null 1162 | points pushBack: 5; 1163 | > null 1164 | points pushBack: 7; 1165 | > null 1166 | points first: 2; 1167 | > [3,5] 1168 | ``` 1169 | 1170 | * **last: (integer)** 1171 | - Returns: vector 1172 | ``` 1173 | Vector create: points; 1174 | > null 1175 | points pushBack: 3; 1176 | > null 1177 | points pushBack: 5; 1178 | > null 1179 | points pushBack: 7; 1180 | > null 1181 | points last: 2; 1182 | > [5,7] 1183 | ``` 1184 | 1185 | * **sliceFromIndex: (integer)** 1186 | - Returns: vector 1187 | ``` 1188 | Vector create: points; 1189 | > null 1190 | points pushBack: 3; 1191 | > null 1192 | points pushBack: 5; 1193 | > null 1194 | points pushBack: 7; 1195 | > null 1196 | points pushBack: 9; 1197 | > null 1198 | points sliceFromIndex: 2; 1199 | > [7,9] 1200 | ``` 1201 | 1202 | * **sliceFromIndex: (integer) toIndex: (integer)** 1203 | - Returns: vector 1204 | ``` 1205 | Vector create: points; 1206 | > null 1207 | points pushBack: 3; 1208 | > null 1209 | points pushBack: 5; 1210 | > null 1211 | points pushBack: 7; 1212 | > null 1213 | points pushBack: 9; 1214 | > null 1215 | points sliceFromIndex: 1 toIndex: 3; 1216 | > [5,7] 1217 | ``` 1218 | 1219 | * **pushBack: (object)** 1220 | - Returns: null 1221 | ``` 1222 | Vector create: points; 1223 | > null 1224 | points pushBack: 3; 1225 | > null 1226 | points pushBack: 5; 1227 | > null 1228 | points pushBack: 7; 1229 | > null 1230 | points get; 1231 | > [3,5,7] 1232 | ``` 1233 | 1234 | * **pushFront: (object)** 1235 | - Returns: null 1236 | ``` 1237 | Vector create: points; 1238 | > null 1239 | points pushFront: 3; 1240 | > null 1241 | points pushFront: 5; 1242 | > null 1243 | points pushFront: 7; 1244 | > null 1245 | points get; 1246 | > [7,5,3] 1247 | ``` 1248 | 1249 | * **popBack** 1250 | - Returns: object 1251 | ``` 1252 | Vector create: points; 1253 | > null 1254 | points pushBack: 3; 1255 | > null 1256 | points pushBack: 5; 1257 | > null 1258 | points pushBack: 7; 1259 | > null 1260 | points popBack; 1261 | > 7 1262 | points get; 1263 | > [3,5] 1264 | ``` 1265 | 1266 | * **popFront** 1267 | - Returns: object 1268 | ``` 1269 | Vector create: points; 1270 | > null 1271 | points pushBack: 3; 1272 | > null 1273 | points pushBack: 5; 1274 | > null 1275 | points pushBack: 7; 1276 | > null 1277 | points popFront; 1278 | > 3 1279 | points get; 1280 | > [5,7] 1281 | ``` 1282 | 1283 | * **popAtIndex: (integer)** 1284 | - Returns: object 1285 | ``` 1286 | Vector create: points; 1287 | > null 1288 | points pushBack: 3; 1289 | > null 1290 | points pushBack: 5; 1291 | > null 1292 | points pushBack: 7; 1293 | > null 1294 | points popAtIndex: 1; 1295 | > 5 1296 | points get; 1297 | > [3,7] 1298 | ``` 1299 | 1300 | * **insert: (object) beforeIndex: (integer)** 1301 | - Returns: null 1302 | ``` 1303 | Vector create: points; 1304 | > null 1305 | points pushBack: 3; 1306 | > null 1307 | points pushBack: 7; 1308 | > null 1309 | points insert: 5 beforeIndex: 1; 1310 | > null 1311 | points get; 1312 | > [3,5,7] 1313 | ``` 1314 | 1315 | * **eraseFromIndex: (integer)** 1316 | - Returns: null 1317 | ``` 1318 | Vector create: points; 1319 | > null 1320 | points pushBack: 3; 1321 | > null 1322 | points pushBack: 5; 1323 | > null 1324 | points pushBack: 7; 1325 | > null 1326 | points eraseFromIndex: 1; 1327 | > null 1328 | points get; 1329 | > [3] 1330 | ``` 1331 | 1332 | * **eraseFromIndex: (integer) toIndex: (integer)** 1333 | - Returns: null 1334 | ``` 1335 | Vector create: points; 1336 | > null 1337 | points pushBack: 3; 1338 | > null 1339 | points pushBack: 5; 1340 | > null 1341 | points pushBack: 7; 1342 | > null 1343 | points eraseFromIndex: 1 toIndex: 2; 1344 | > null 1345 | points get; 1346 | > [3,7] 1347 | ``` 1348 | 1349 | * **removeFirst: (object)** 1350 | - Returns: null 1351 | ``` 1352 | Vector create: points; 1353 | > null 1354 | points pushBack: 3; 1355 | > null 1356 | points pushBack: 5; 1357 | > null 1358 | points pushBack: 3; 1359 | > null 1360 | points pushBack: 5; 1361 | > null 1362 | points removeFirst: 5; 1363 | > null 1364 | points get; 1365 | > [3,3,5] 1366 | ``` 1367 | 1368 | * **removeFirst: (object) fromIndex: (integer)** 1369 | - Returns: null 1370 | ``` 1371 | Vector create: points; 1372 | > null 1373 | points pushBack: 3; 1374 | > null 1375 | points pushBack: 5; 1376 | > null 1377 | points pushBack: 3; 1378 | > null 1379 | points pushBack: 5; 1380 | > null 1381 | points removeFirst: 5 fromIndex: 2; 1382 | > null 1383 | points get; 1384 | > [3,5,3] 1385 | ``` 1386 | 1387 | * **removeAll: (object)** 1388 | - Returns: null 1389 | ``` 1390 | Vector create: points; 1391 | > null 1392 | points pushBack: 3; 1393 | > null 1394 | points pushBack: 5; 1395 | > null 1396 | points pushBack: 3; 1397 | > null 1398 | points pushBack: 5; 1399 | > null 1400 | points removeAll: 3; 1401 | > null 1402 | points get; 1403 | > [5,5] 1404 | ``` 1405 | 1406 | * **replaceFirst: (object) with: (object)** 1407 | - Returns: null 1408 | ``` 1409 | Vector create: points; 1410 | > null 1411 | points pushBack: 3; 1412 | > null 1413 | points pushBack: 5; 1414 | > null 1415 | points pushBack: 3; 1416 | > null 1417 | points pushBack: 5; 1418 | > null 1419 | points replaceFirst: 5 with: 7; 1420 | > null 1421 | points get; 1422 | > [3,7,3,5] 1423 | ``` 1424 | 1425 | * **replaceFirst: (object) fromIndex: (integer) with: (object)** 1426 | - Returns: null 1427 | ``` 1428 | Vector create: points; 1429 | > null 1430 | points pushBack: 3; 1431 | > null 1432 | points pushBack: 5; 1433 | > null 1434 | points pushBack: 3; 1435 | > null 1436 | points pushBack: 5; 1437 | > null 1438 | points replaceFirst: 5 fromIndex: 2 with: 7; 1439 | > null 1440 | points get; 1441 | > [3,5,3,7] 1442 | ``` 1443 | 1444 | * **replaceAll: (object) with: (object)** 1445 | - Returns: null 1446 | ``` 1447 | Vector create: points; 1448 | > null 1449 | points pushBack: 3; 1450 | > null 1451 | points pushBack: 5; 1452 | > null 1453 | points pushBack: 3; 1454 | > null 1455 | points pushBack: 5; 1456 | > null 1457 | points replaceAll: 5 with: 7; 1458 | > null 1459 | points get; 1460 | > [3,7,3,7] 1461 | ``` 1462 | 1463 | * **sort** 1464 | - Returns: null 1465 | ``` 1466 | Vector create: points; 1467 | > null 1468 | points pushBack: 7; 1469 | > null 1470 | points pushBack: 3; 1471 | > null 1472 | points pushBack: 5; 1473 | > null 1474 | points sort; 1475 | > null 1476 | points get; 1477 | > [3,5,7] 1478 | ``` 1479 | 1480 | * **reverse** 1481 | - Returns: null 1482 | ``` 1483 | Vector create: points; 1484 | > null 1485 | points pushBack: 3; 1486 | > null 1487 | points pushBack: 5; 1488 | > null 1489 | points pushBack: 7; 1490 | > null 1491 | points reverse; 1492 | > null 1493 | points get; 1494 | > [7,5,3] 1495 | ``` 1496 | 1497 | * **clear** 1498 | - Returns: null 1499 | ``` 1500 | Vector create: points; 1501 | > null 1502 | points pushBack: 3; 1503 | > null 1504 | points pushBack: 5; 1505 | > null 1506 | points pushBack: 7; 1507 | > null 1508 | points clear; 1509 | > null 1510 | points get; 1511 | > [] 1512 | ``` 1513 | 1514 | ### Set 1515 | Sets are containers that store unique elements. 1516 | 1517 | #### Constructors: 1518 | * **create: (variable)** 1519 | - Returns: null 1520 | ``` 1521 | Set create: players; 1522 | > null 1523 | players get; 1524 | > {} 1525 | ``` 1526 | 1527 | * **createIfNotExists: (variable)** 1528 | - Returns: null 1529 | ``` 1530 | Set createIfNotExists: players; 1531 | > null 1532 | players get; 1533 | > {} 1534 | ``` 1535 | 1536 | #### Methods: 1537 | * **get** 1538 | - Returns: set 1539 | ``` 1540 | Set create: players; 1541 | > null 1542 | players get; 1543 | > {} 1544 | ``` 1545 | 1546 | * **isEmpty?** 1547 | - Returns: boolean 1548 | ``` 1549 | Set create: players; 1550 | > null 1551 | players isEmpty?; 1552 | > true 1553 | players add: "Babe Ruth"; 1554 | > null 1555 | players isEmpty?; 1556 | > false 1557 | ``` 1558 | 1559 | * **contains? (object)** 1560 | - Returns: boolean 1561 | ``` 1562 | Set create: players; 1563 | > null 1564 | players contains? "Babe Ruth"; 1565 | > false 1566 | players add: "Babe Ruth"; 1567 | > null 1568 | players contains? "Babe Ruth"; 1569 | > true 1570 | ``` 1571 | 1572 | * **size** 1573 | - Returns: integer 1574 | ``` 1575 | Set create: players; 1576 | > null 1577 | players add: "Babe Ruth"; 1578 | > null 1579 | players add: "David Ortiz"; 1580 | > null 1581 | players add: "Paulo Orlando"; 1582 | > null 1583 | players size; 1584 | > 3 1585 | ``` 1586 | 1587 | * **add: (object)** 1588 | - Returns: null 1589 | ``` 1590 | Set create: players; 1591 | > null 1592 | players add: "Babe Ruth"; 1593 | > null 1594 | players get; 1595 | > {"Babe Ruth"} 1596 | ``` 1597 | 1598 | * **remove: (object)** 1599 | - Returns: null 1600 | ``` 1601 | Set create: players; 1602 | > null 1603 | players add: "Babe Ruth"; 1604 | > null 1605 | players remove: "Babe Ruth"; 1606 | > null 1607 | players get; 1608 | > {} 1609 | ``` 1610 | 1611 | * **clear** 1612 | - Returns: null 1613 | ``` 1614 | Set create: players; 1615 | > null 1616 | players add: "Babe Ruth"; 1617 | > null 1618 | players add: "David Ortiz"; 1619 | > null 1620 | players add: "Paulo Orlando"; 1621 | > null 1622 | players clear; 1623 | > null 1624 | players get; 1625 | > {} 1626 | ``` 1627 | 1628 | ### Dictionary 1629 | Dictionaries are associative containers that store keys and their associated values. 1630 | 1631 | #### Constructors: 1632 | * **create: (variable)** 1633 | - Returns: null 1634 | ``` 1635 | Dictionary create: ERAs; 1636 | > null 1637 | ERAs get; 1638 | > () 1639 | ``` 1640 | 1641 | * **createIfNotExists: (variable)** 1642 | - Returns: null 1643 | ``` 1644 | Dictionary createIfNotExists: ERAs; 1645 | > null 1646 | ERAs get; 1647 | > () 1648 | ``` 1649 | 1650 | #### Methods: 1651 | * **get** 1652 | - Returns: dictionary 1653 | ``` 1654 | Dictionary create: ERAs; 1655 | > null 1656 | ERAs get; 1657 | > () 1658 | ``` 1659 | 1660 | * **isEmpty?** 1661 | - Returns: boolean 1662 | ``` 1663 | Dictionary create: ERAs; 1664 | > null 1665 | ERAs isEmpty?; 1666 | > true 1667 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 1668 | > null 1669 | ERAs isEmpty?; 1670 | > false 1671 | ``` 1672 | 1673 | * **containsKey? (object)** 1674 | - Returns: boolean 1675 | ``` 1676 | Dictionary create: ERAs; 1677 | > null 1678 | ERAs containsKey? "Ed Walsh"; 1679 | > false 1680 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 1681 | > null 1682 | ERAs containsKey? "Ed Walsh"; 1683 | > true 1684 | ``` 1685 | 1686 | * **size** 1687 | - Returns: integer 1688 | ``` 1689 | Dictionary create: ERAs; 1690 | > null 1691 | ERAs size; 1692 | > 0 1693 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 1694 | > null 1695 | ERAs size; 1696 | > 1 1697 | ``` 1698 | 1699 | * **keys** 1700 | - Returns: vector 1701 | ``` 1702 | Dictionary create: ERAs; 1703 | > null 1704 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 1705 | > null 1706 | ERAs associateValue: 2.21 withKey: "Mariano Rivera"; 1707 | > null 1708 | ERAs associateValue: 2.39 withKey: "Clayton Kershaw"; 1709 | > null 1710 | ERAs keys; 1711 | > ["Clayton Kershaw","Ed Walsh","Mariano Rivera"] 1712 | ``` 1713 | 1714 | * **values** 1715 | - Returns: vector 1716 | ``` 1717 | Dictionary create: ERAs; 1718 | > null 1719 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 1720 | > null 1721 | ERAs associateValue: 2.21 withKey: "Mariano Rivera"; 1722 | > null 1723 | ERAs associateValue: 2.39 withKey: "Clayton Kershaw"; 1724 | > null 1725 | ERAs values; 1726 | > [2.390,1.820,2.210] 1727 | ``` 1728 | 1729 | * **getValueForKey: (object)** 1730 | - Returns: object 1731 | ``` 1732 | Dictionary create: ERAs; 1733 | > null 1734 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 1735 | > null 1736 | ERAs getValueForKey: "Ed Walsh"; 1737 | > 1.820 1738 | ``` 1739 | 1740 | * **associateValue: (object) withKey: (object)** 1741 | - Returns: null 1742 | ``` 1743 | Dictionary create: ERAs; 1744 | > null 1745 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 1746 | > null 1747 | ERAs get; 1748 | > (("Ed Walsh",1.82)) 1749 | ``` 1750 | 1751 | * **removeKey: (object)** 1752 | - Returns: null 1753 | ``` 1754 | Dictionary create: ERAs; 1755 | > null 1756 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 1757 | > null 1758 | ERAs removeKey: "Ed Walsh"; 1759 | > null 1760 | ERAs get; 1761 | > () 1762 | ``` 1763 | 1764 | * **clear** 1765 | - Returns: null 1766 | ``` 1767 | Dictionary create: ERAs; 1768 | > null 1769 | ERAs associateValue: 1.82 withKey: "Ed Walsh"; 1770 | > null 1771 | ERAs associateValue: 2.21 withKey: "Mariano Rivera"; 1772 | > null 1773 | ERAs associateValue: 2.39 withKey: "Clayton Kershaw"; 1774 | > null 1775 | ERAs clear; 1776 | > null 1777 | ERAs get; 1778 | > () 1779 | ``` 1780 | 1781 | ### Context 1782 | Context is an execution environment. 1783 | 1784 | #### Methods: 1785 | * **listNamespaces** 1786 | - Returns: vector 1787 | ``` 1788 | Boolean create: std::bool withValue: true; 1789 | > null 1790 | Integer create: mynamespace::i withValue: 42; 1791 | > null 1792 | Context listNamespaces; 1793 | > [mynamespace,std] 1794 | ``` 1795 | 1796 | * **listVariables** 1797 | - Returns: vector 1798 | ``` 1799 | Boolean create: std::bool withValue: true; 1800 | > null 1801 | Integer create: i withValue: 42; 1802 | > null 1803 | Context listVariables; 1804 | > [i,std::bool] 1805 | ``` 1806 | 1807 | * **listVariablesOfNamespace: (namespace)** 1808 | - Returns: vector 1809 | ``` 1810 | Boolean create: std::bool withValue: true; 1811 | > null 1812 | Character create: std::char withValue: 'a'; 1813 | > null 1814 | Integer create: mynamespace::i withValue: 42; 1815 | > null 1816 | Context listVariablesOfNamespace: std; 1817 | > [std::bool,std::char] 1818 | ``` 1819 | 1820 | * **deleteVariable: (variable)** 1821 | - Returns: null 1822 | ``` 1823 | Boolean create: bool withValue: true; 1824 | > null 1825 | Integer create: i withValue: 42; 1826 | > null 1827 | Context deleteVariable: bool; 1828 | > null 1829 | Context listVariables; 1830 | > [i] 1831 | ``` 1832 | 1833 | * **deleteVariablesOfNamespace: (namespace)** 1834 | - Returns: null 1835 | ``` 1836 | Boolean create: std::bool withValue: true; 1837 | > null 1838 | Character create: std::char withValue: 'a'; 1839 | > null 1840 | Integer create: i withValue: 42; 1841 | > null 1842 | Context deleteVariablesOfNamespace: std; 1843 | > null 1844 | Context listVariables; 1845 | > [i] 1846 | ``` 1847 | 1848 | * **getFloatPrecision** 1849 | - Returns: integer 1850 | ``` 1851 | Context setFloatPrecision: 5; 1852 | > null 1853 | Context getFloatPrecision; 1854 | > 5 1855 | ``` 1856 | 1857 | * **setFloatPrecision: (integer)** 1858 | - Returns: null 1859 | ``` 1860 | Float create: f withValue: 0.1; 1861 | > null 1862 | Context setFloatPrecision: 5; 1863 | > null 1864 | f get; 1865 | > 0.10000 1866 | ``` 1867 | 1868 | * **getFloatComparisonTolerance** 1869 | - Returns: float 1870 | ``` 1871 | Context setFloatComparisonTolerance: 1e-3; 1872 | > null 1873 | Context getFloatComparisonTolerance; 1874 | > 0.001 1875 | ``` 1876 | 1877 | * **setFloatComparisonTolerance: (float)** 1878 | - Returns: null 1879 | ``` 1880 | Float create: f withValue: 0.0; 1881 | > null 1882 | Context setFloatComparisonTolerance: 1.0; 1883 | > null 1884 | f isEqualTo? 0.9; 1885 | > true 1886 | Context setFloatComparisonTolerance: 1e-3; 1887 | > null 1888 | f isEqualTo? 0.9; 1889 | > false 1890 | ``` 1891 | 1892 | ### Connection 1893 | Connection is an object that represents the TCP connection with the server. 1894 | 1895 | #### Methods: 1896 | * **authenticateWithPassword: (string)** 1897 | - Returns: null 1898 | ``` 1899 | Connection authenticateWithPassword: "password"; 1900 | > null 1901 | ``` 1902 | 1903 | * **close** 1904 | - Returns: null 1905 | ``` 1906 | Connection close; 1907 | > null 1908 | ``` 1909 | 1910 | ## Future work 1911 | * Persistence on disk. 1912 | * Transaction manager. 1913 | * Containers like lists, stacks, queues, multisets and multidictionaries. 1914 | -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /src/context.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include "context.h" 30 | #include "exceptions.h" 31 | #include "grammar.h" 32 | #include "str_utils.h" 33 | 34 | // Initialize the singleton instance. 35 | Context* Context::_instance = NULL; 36 | 37 | Context* Context::get_instance(const std::string& logfile_name, int float_precision, float float_comparison_tolerance, 38 | bool is_quiet_mode) { 39 | delete _instance; 40 | _instance = new Context(logfile_name, float_precision, float_comparison_tolerance, is_quiet_mode); 41 | return _instance; 42 | } 43 | 44 | Context* Context::get_instance() { 45 | return _instance; 46 | } 47 | 48 | Context::Context(const std::string& logfile_name, int float_precision, float float_comparison_tolerance, 49 | bool is_quiet_mode) : _float_precision(float_precision), 50 | _float_comparison_tolerance(float_comparison_tolerance), 51 | _is_quiet_mode(is_quiet_mode) { 52 | if (logfile_name != "") 53 | _logfile.open(logfile_name, std::ios::out | std::ios::app); 54 | } 55 | 56 | Context::~Context() { 57 | if (_logfile.is_open()) 58 | _logfile.close(); 59 | _instance = NULL; 60 | } 61 | 62 | int Context::get_float_precision() { 63 | return _float_precision; 64 | } 65 | 66 | void Context::set_float_precision(int float_precision) { 67 | _float_precision = float_precision; 68 | } 69 | 70 | float Context::get_float_comparison_tolerance() { 71 | return _float_comparison_tolerance; 72 | } 73 | 74 | void Context::set_float_comparison_tolerance(float float_comparison_tolerance) { 75 | _float_comparison_tolerance = float_comparison_tolerance; 76 | } 77 | 78 | std::string Context::execute_in_type(const Parser& parser) { 79 | std::shared_ptr instance; 80 | std::string type = str_utils::remove_spaces(parser.actor()); 81 | std::string message_name = parser.message_name(); 82 | if (type == "Boolean") 83 | instance = std::make_shared(message_name, parser.arguments()); 84 | else if (type == "Character") 85 | instance = std::make_shared(message_name, parser.arguments()); 86 | else if (type == "Integer") 87 | instance = std::make_shared(message_name, parser.arguments()); 88 | else if (type == "Float") 89 | instance = std::make_shared(message_name, parser.arguments()); 90 | else if (type == "String") 91 | instance = std::make_shared(message_name, parser.arguments()); 92 | else if (str_utils::starts_with(type, "Vector")) 93 | instance = std::make_shared(type.substr(7, int(type.size()) - 8), message_name, 94 | parser.arguments()); 95 | else if (str_utils::starts_with(type, "Set")) 96 | instance = std::make_shared(type.substr(4, int(type.size()) - 5), message_name, 97 | parser.arguments()); 98 | else if (str_utils::starts_with(type, "Dictionary")) { 99 | std::string types_of_dictionary = type.substr(11, int(type.size()) - 12); 100 | for (int i = 0; i < int(types_of_dictionary.size()); i++) 101 | if (types_of_dictionary[i] == ',') 102 | instance = std::make_shared(types_of_dictionary.substr(0, i), 103 | types_of_dictionary.substr(i + 1), 104 | message_name, parser.arguments()); 105 | } 106 | if (_instances.find(instance->name()) == _instances.end()) { 107 | _instances[instance->name()] = instance; 108 | return "null"; 109 | } 110 | if (str_utils::starts_with(message_name, "createIfNotExists:")) 111 | return "null"; 112 | throw EXC_VARIABLE_NAME_ALREADY_USED; 113 | } 114 | 115 | std::string Context::execute_in_context(const Parser& parser) { 116 | std::string message_name = parser.message_name(); 117 | if (message_name == "listNamespaces") 118 | return op_listNamespaces(parser.arguments()); 119 | else if (message_name == "listVariables") 120 | return op_listVariables(parser.arguments()); 121 | else if (message_name == "listVariablesOfNamespace:") 122 | return op_listVariablesOfNamespace(parser.arguments()); 123 | else if (message_name == "deleteVariable:") 124 | return op_deleteVariable(parser.arguments()); 125 | else if (message_name == "deleteVariablesOfNamespace:") 126 | return op_deleteVariablesOfNamespace(parser.arguments()); 127 | else if (message_name == "getFloatPrecision") 128 | return op_getFloatPrecision(parser.arguments()); 129 | else if (message_name == "setFloatPrecision:") 130 | return op_setFloatPrecision(parser.arguments()); 131 | else if (message_name == "getFloatComparisonTolerance") 132 | return op_getFloatComparisonTolerance(parser.arguments()); 133 | else if (message_name == "setFloatComparisonTolerance:") 134 | return op_setFloatComparisonTolerance(parser.arguments()); 135 | throw EXC_INVALID_MESSAGE; 136 | } 137 | 138 | std::string Context::execute_in_variable(const Parser& parser) { 139 | auto instance = _instances.find(parser.actor()); 140 | if (instance == _instances.end()) 141 | throw EXC_UNEXISTENT_VARIABLE; 142 | return instance->second->receive(parser.message_name(), parser.arguments()); 143 | } 144 | 145 | std::string Context::execute(const std::string& input, std::shared_ptr session) { 146 | std::string output; 147 | try { 148 | Parser parser(input); 149 | std::string actor = parser.actor(); 150 | if (Grammar::is_type(actor)) 151 | output = execute_in_type(parser); 152 | else if (Grammar::is_context(actor)) 153 | output = execute_in_context(parser); 154 | else if (Grammar::is_variable(actor)) 155 | output = execute_in_variable(parser); 156 | else if (Grammar::is_connection(actor)) 157 | output = session->receive(parser.message_name(), parser.arguments()); 158 | } 159 | catch (const char* exception) { 160 | output = std::string(exception); 161 | } 162 | catch (...) { 163 | output = std::string(EXC_UNKNOWN_ERROR); 164 | } 165 | char timestamp[32]; 166 | time_t now = time(NULL); 167 | strftime(timestamp, sizeof(timestamp), "[%F %T]", localtime(&now)); 168 | if (_logfile.is_open()) 169 | _logfile << timestamp << " " << str_utils::trim(input) << " -> " << output << std::endl; 170 | else if (!_is_quiet_mode) 171 | std::cout << timestamp << " " << str_utils::trim(input) << " -> " << output << std::endl; 172 | return output; 173 | } 174 | 175 | std::string Context::op_listNamespaces(const std::vector& arguments) { 176 | if (arguments.size() != 0) 177 | throw EXC_WRONG_NUMBER_OF_ARGUMENTS; 178 | std::set namespaces; 179 | for (auto it = _instances.begin(); it != _instances.end(); it++) 180 | for (int i = 0; i < int(it->first.size()) - 1; i++) 181 | if (it->first[i] == ':' && it->first[i + 1] == ':') 182 | namespaces.insert(it->first.substr(0, i)); 183 | std::string elements_str; 184 | for (auto it = namespaces.begin(); it != namespaces.end(); it++) { 185 | if (it != namespaces.begin()) 186 | elements_str += ","; 187 | elements_str += *it; 188 | } 189 | return "[" + elements_str + "]"; 190 | } 191 | 192 | std::string Context::op_listVariables(const std::vector& arguments) { 193 | if (arguments.size() != 0) 194 | throw EXC_WRONG_NUMBER_OF_ARGUMENTS; 195 | std::string elements_str; 196 | for (auto it = _instances.begin(); it != _instances.end(); it++) { 197 | if (it != _instances.begin()) 198 | elements_str += ","; 199 | elements_str += it->first; 200 | } 201 | return "[" + elements_str + "]"; 202 | } 203 | 204 | std::string Context::op_listVariablesOfNamespace(const std::vector& arguments) { 205 | if (arguments.size() != 1) 206 | throw EXC_WRONG_NUMBER_OF_ARGUMENTS; 207 | if (!Grammar::is_namespace(arguments[0])) 208 | throw EXC_INVALID_ARGUMENT; 209 | std::string elements_str; 210 | for (auto it = _instances.begin(); it != _instances.end(); it++) { 211 | if (!str_utils::starts_with(it->first, arguments[0] + "::")) 212 | continue; 213 | if (elements_str.size() > 0) 214 | elements_str += ","; 215 | elements_str += it->first; 216 | } 217 | return "[" + elements_str + "]"; 218 | } 219 | 220 | std::string Context::op_deleteVariable(const std::vector& arguments) { 221 | if (arguments.size() != 1) 222 | throw EXC_WRONG_NUMBER_OF_ARGUMENTS; 223 | if (!Grammar::is_variable(arguments[0])) 224 | throw EXC_INVALID_ARGUMENT; 225 | for (auto it = _instances.begin(); it != _instances.end(); it++) 226 | if (it->first == arguments[0]) { 227 | _instances.erase(it); 228 | return "null"; 229 | } 230 | throw EXC_UNEXISTENT_VARIABLE; 231 | } 232 | 233 | std::string Context::op_deleteVariablesOfNamespace(const std::vector& arguments) { 234 | if (arguments.size() != 1) 235 | throw EXC_WRONG_NUMBER_OF_ARGUMENTS; 236 | if (!Grammar::is_namespace(arguments[0])) 237 | throw EXC_INVALID_ARGUMENT; 238 | std::vector>::iterator> instances_to_be_deleted; 239 | for (auto it = _instances.begin(); it != _instances.end(); it++) 240 | if (str_utils::starts_with(it->first, arguments[0] + "::")) 241 | instances_to_be_deleted.push_back(it); 242 | for (auto it = instances_to_be_deleted.begin(); it != instances_to_be_deleted.end(); it++) 243 | _instances.erase(*it); 244 | return "null"; 245 | } 246 | 247 | std::string Context::op_getFloatPrecision(const std::vector& arguments) { 248 | return IntegerInstance(_float_precision).representation(); 249 | } 250 | 251 | std::string Context::op_setFloatPrecision(const std::vector& arguments) { 252 | if (arguments.size() != 1) 253 | throw EXC_WRONG_NUMBER_OF_ARGUMENTS; 254 | int float_precision = IntegerInstance(arguments[0]).value(); 255 | if (float_precision <= 0) 256 | throw EXC_INVALID_ARGUMENT; 257 | _float_precision = float_precision; 258 | return "null"; 259 | } 260 | 261 | std::string Context::op_getFloatComparisonTolerance(const std::vector& arguments) { 262 | return FloatInstance(_float_comparison_tolerance).representation(); 263 | } 264 | 265 | std::string Context::op_setFloatComparisonTolerance(const std::vector& arguments) { 266 | if (arguments.size() != 1) 267 | throw EXC_WRONG_NUMBER_OF_ARGUMENTS; 268 | float float_comparison_tolerance = FloatInstance(arguments[0]).value(); 269 | if (float_comparison_tolerance < 0) 270 | throw EXC_INVALID_ARGUMENT; 271 | _float_comparison_tolerance = float_comparison_tolerance; 272 | return "null"; 273 | } 274 | -------------------------------------------------------------------------------- /src/context.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KNUCKLEBALL_CONTEXT_H 27 | #define KNUCKLEBALL_CONTEXT_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "instance.h" 36 | #include "parser.h" 37 | #include "server.h" 38 | 39 | class Context { 40 | private: 41 | // Singleton instance: 42 | static Context *_instance; 43 | 44 | // Attributes: 45 | std::ofstream _logfile; 46 | int _float_precision; 47 | float _float_comparison_tolerance; 48 | bool _is_quiet_mode; 49 | std::map> _instances; 50 | 51 | // Constructor: 52 | Context(const std::string& logfile_name, int float_precision, float float_comparison_tolerance, bool is_quiet_mode); 53 | 54 | // Input processing methods: 55 | std::string execute_in_type(const Parser& parser); 56 | std::string execute_in_context(const Parser& parser); 57 | std::string execute_in_variable(const Parser& parser); 58 | 59 | // Operators: 60 | std::string op_listNamespaces(const std::vector& arguments); 61 | std::string op_listVariables(const std::vector& arguments); 62 | std::string op_listVariablesOfNamespace(const std::vector& arguments); 63 | std::string op_deleteVariable(const std::vector& arguments); 64 | std::string op_deleteVariablesOfNamespace(const std::vector& arguments); 65 | std::string op_getFloatPrecision(const std::vector& arguments); 66 | std::string op_setFloatPrecision(const std::vector& arguments); 67 | std::string op_getFloatComparisonTolerance(const std::vector& arguments); 68 | std::string op_setFloatComparisonTolerance(const std::vector& arguments); 69 | 70 | // Delete copy constructor and assignment operator: 71 | Context(const Context& other) = delete; 72 | Context& operator=(const Context& other) = delete; 73 | public: 74 | // Singleton getter: 75 | static Context* get_instance(const std::string& logfile_name, int float_precision, 76 | float float_comparison_tolerance, bool is_quiet_mode); 77 | static Context* get_instance(); 78 | 79 | // Destructor: 80 | ~Context(); 81 | 82 | // Decimal precision to be used to format floating-point values. 83 | int get_float_precision(); 84 | void set_float_precision(int float_precision); 85 | 86 | // Tolerance to be used to compare floating-point values. 87 | float get_float_comparison_tolerance(); 88 | void set_float_comparison_tolerance(float float_comparison_tolerance); 89 | 90 | // Execute the input string and return a string or throw an exception. 91 | std::string execute(const std::string& input, std::shared_ptr session=nullptr); 92 | }; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /src/exceptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KNUCKLEBALL_EXCEPTIONS_H 27 | #define KNUCKLEBALL_EXCEPTIONS_H 28 | 29 | #define EXC_INVALID_STATEMENT "SyntaxError: invalid statement." 30 | #define EXC_INVALID_ARGUMENT "RuntimeError: invalid argument." 31 | #define EXC_INVALID_MESSAGE "RuntimeError: invalid message." 32 | #define EXC_VARIABLE_NAME_ALREADY_USED "RuntimeError: variable name already used." 33 | #define EXC_UNEXISTENT_VARIABLE "RuntimeError: name cannot be resolved to a variable." 34 | #define EXC_WRONG_NUMBER_OF_ARGUMENTS "RuntimeError: wrong number of arguments." 35 | #define EXC_INVALID_COMPARISON "RuntimeError: cannot compare these two types." 36 | #define EXC_NOT_AUTHENTICATED "AuthenticationError: not authenticated." 37 | #define EXC_WRONG_PASSWORD "AuthenticationError: wrong password." 38 | #define EXC_UNKNOWN_ERROR "RuntimeError: unknown error." 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/grammar.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "grammar.h" 27 | #include "str_utils.h" 28 | 29 | std::set Grammar::RESERVED_WORDS { 30 | "null", 31 | "true", 32 | "false", 33 | "Connection", 34 | "Context", 35 | "Boolean", 36 | "Character", 37 | "Integer", 38 | "Float", 39 | "String", 40 | "Vector", 41 | "Set", 42 | "Dictionary" 43 | }; 44 | 45 | bool Grammar::is_spaces(const std::string& str) { 46 | return str_utils::ltrim(str).size() == 0; 47 | } 48 | 49 | bool Grammar::is_boolean_type(const std::string& str) { 50 | return str == "Boolean"; 51 | } 52 | 53 | bool Grammar::is_boolean_value(const std::string& str) { 54 | return str == "true" || str == "false"; 55 | } 56 | 57 | bool Grammar::is_character_type(const std::string& str) { 58 | return str == "Character"; 59 | } 60 | 61 | bool Grammar::is_character_value(const std::string& str) { 62 | if (str.size() != 3) 63 | return false; 64 | return str[0] == '\'' && str[2] == '\''; 65 | } 66 | 67 | bool Grammar::is_integer_type(const std::string& str) { 68 | return str == "Integer"; 69 | } 70 | 71 | bool Grammar::is_integer_value(const std::string& str) { 72 | if (str.size() == 0) 73 | return false; 74 | if (!str_utils::is_numeric(str[0]) && str[0] != '+' && str[0] != '-') 75 | return false; 76 | for (int i = 1; i < int(str.size()); i++) 77 | if (!str_utils::is_numeric(str[i])) 78 | return false; 79 | return str_utils::is_numeric(str[0]) || str.size() > 1; 80 | } 81 | 82 | bool Grammar::is_float_type(const std::string& str) { 83 | return str == "Float"; 84 | } 85 | 86 | bool Grammar::is_float_value(const std::string& str) { 87 | if (str.size() == 0) 88 | return false; 89 | int count_point = 0, count_numeric = 0; 90 | for (int i = (str[0] == '+' || str[0] == '-') ? 1 : 0; i < int(str.size()); i++) { 91 | if (!str_utils::is_numeric(str[i]) && str[i] != '.') { 92 | if (str[i] != 'e') 93 | return false; 94 | return count_point <= 1 && count_numeric > 0 && is_integer_value(str.substr(i + 1)); 95 | } 96 | if (str[i] == '.') 97 | count_point++; 98 | if (str_utils::is_numeric(str[i])) 99 | count_numeric++; 100 | } 101 | return count_point <= 1 && count_numeric > 0; 102 | } 103 | 104 | bool Grammar::is_string_type(const std::string& str) { 105 | return str == "String"; 106 | } 107 | 108 | bool Grammar::is_string_value(const std::string& str) { 109 | if (str.size() < 2) 110 | return false; 111 | if (str[0] != '"' || str[int(str.size()) - 1] != '"') 112 | return false; 113 | for (int i = 1; i < int(str.size()) - 1; i++) 114 | if (str[i] == '"') 115 | for (int j = i - 1; j >= 0; j--) 116 | if (str[j] != '\\') { 117 | if ((i - j) % 2 == 1) 118 | return false; 119 | break; 120 | } 121 | for (int i = int(str.size()) - 2; i > 0; i--) 122 | if (str[i] != '\\') 123 | return (int(str.size()) - 1 - i) % 2 == 1; 124 | return str.size() % 2 == 0; 125 | } 126 | 127 | bool Grammar::is_object_type(const std::string& str) { 128 | return is_boolean_type(str) || is_character_type(str) || is_integer_type(str) || is_float_type(str) || 129 | is_string_type(str); 130 | } 131 | 132 | bool Grammar::is_object_value(const std::string& str) { 133 | return is_boolean_value(str) || is_character_value(str) || is_integer_value(str) || is_float_value(str) || 134 | is_string_value(str); 135 | } 136 | 137 | bool Grammar::is_vector_type(const std::string& str) { 138 | if (!str_utils::starts_with(str, "Vector<") || !str_utils::ends_with(str, ">")) 139 | return false; 140 | return is_object_type(str_utils::trim(str.substr(7, int(str.size()) - 8))); 141 | } 142 | 143 | bool Grammar::is_set_type(const std::string& str) { 144 | if (!str_utils::starts_with(str, "Set<") || !str_utils::ends_with(str, ">")) 145 | return false; 146 | return is_object_type(str_utils::trim(str.substr(4, int(str.size()) - 5))); 147 | } 148 | 149 | bool Grammar::is_dictionary_type(const std::string& str) { 150 | if (!str_utils::starts_with(str, "Dictionary<") || !str_utils::ends_with(str, ">")) 151 | return false; 152 | std::string types_of_dictionary = str.substr(11, int(str.size()) - 12); 153 | for (int i = 0; i < int(types_of_dictionary.size()); i++) 154 | if (types_of_dictionary[i] == ',') 155 | return is_object_type(str_utils::trim(types_of_dictionary.substr(0, i))) && 156 | is_object_type(str_utils::trim(types_of_dictionary.substr(i + 1))); 157 | return false; 158 | } 159 | 160 | bool Grammar::is_container_type(const std::string& str) { 161 | return is_vector_type(str) || is_set_type(str) || is_dictionary_type(str); 162 | } 163 | 164 | bool Grammar::is_type(const std::string& str) { 165 | return is_object_type(str) || is_container_type(str); 166 | } 167 | 168 | bool Grammar::is_connection(const std::string& str) { 169 | return str == "Connection"; 170 | } 171 | 172 | bool Grammar::is_context(const std::string& str) { 173 | return str == "Context"; 174 | } 175 | 176 | bool Grammar::is_reserved_word(const std::string& str) { 177 | return RESERVED_WORDS.find(str) != RESERVED_WORDS.end(); 178 | } 179 | 180 | bool Grammar::is_identifier(const std::string& str) { 181 | if (str.size() == 0 || !str_utils::is_alpha(str[0])) 182 | return false; 183 | for (int i = 1; i < int(str.size()); i++) 184 | if (!str_utils::is_alphanumeric(str[i]) && str[i] != '_') 185 | return false; 186 | return !is_reserved_word(str); 187 | } 188 | 189 | bool Grammar::is_namespace(const std::string& str) { 190 | return is_identifier(str); 191 | } 192 | 193 | bool Grammar::is_variable(const std::string& str) { 194 | if (str.size() == 0) 195 | return false; 196 | for (int i = 0; i < int(str.size()) - 1; i++) 197 | if (str[i] == ':' && str[i + 1] == ':') 198 | return is_namespace(str.substr(0, i)) && is_identifier(str.substr(i + 2)); 199 | return is_identifier(str); 200 | } 201 | 202 | bool Grammar::is_actor(const std::string& str) { 203 | return is_connection(str) || is_context(str) || is_type(str) || is_variable(str); 204 | } 205 | 206 | bool Grammar::is_unary_message(const std::string& str) { 207 | return str.size() > 0 && 208 | (is_identifier(str) || (str[int(str.size()) - 1] == '?' && is_identifier(str.substr(0, int(str.size()) - 1)))); 209 | } 210 | 211 | bool Grammar::is_keyword_message_token(const std::string& str) { 212 | return str.size() > 0 && (str[int(str.size()) - 1] == ':' || str[int(str.size()) - 1] == '?') && 213 | is_identifier(str.substr(0, int(str.size()) - 1)); 214 | } 215 | 216 | bool Grammar::is_keyword_message_argument(const std::string& str) { 217 | return is_object_value(str) || is_namespace(str) || is_variable(str); 218 | } 219 | 220 | bool Grammar::is_keyword_message_part(const std::string& str) { 221 | for (int i = 0; i < int(str.size()); i++) 222 | if (str[i] == ':' || str[i] == '?') 223 | return is_keyword_message_token(str.substr(0, i + 1)) && 224 | is_keyword_message_argument(str_utils::ltrim(str.substr(i + 1))); 225 | return false; 226 | } 227 | 228 | bool Grammar::is_keyword_message(const std::string& str) { 229 | if (is_keyword_message_part(str)) 230 | return true; 231 | for (int i = 0; i < int(str.size()); i++) 232 | if (str_utils::is_space(str[i]) && is_keyword_message_part(str.substr(0, i)) && 233 | is_keyword_message(str_utils::ltrim(str.substr(i + 1)))) 234 | return true; 235 | return false; 236 | } 237 | 238 | bool Grammar::is_statement(const std::string& str) { 239 | std::string trimmed_str = str_utils::trim(str); 240 | if (trimmed_str.size() == 0 || trimmed_str[int(trimmed_str.size()) - 1] != ';') 241 | return false; 242 | trimmed_str = str_utils::rtrim(trimmed_str.substr(0, int(trimmed_str.size()) - 1)); 243 | for (int i = 0; i < int(trimmed_str.size()); i++) 244 | if (str_utils::is_space(trimmed_str[i]) && is_actor(trimmed_str.substr(0, i))) { 245 | std::string message = str_utils::ltrim(trimmed_str.substr(i + 1)); 246 | return (is_unary_message(message) || is_keyword_message(message)); 247 | } 248 | return false; 249 | } 250 | -------------------------------------------------------------------------------- /src/grammar.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KNUCKLEBALL_GRAMMAR_H 27 | #define KNUCKLEBALL_GRAMMAR_H 28 | 29 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 30 | //////////////////////////////////////////////////// GRAMMAR RULES ///////////////////////////////////////////////////// 31 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 32 | // 33 | // --> \s* 34 | // --> Boolean 35 | // --> true | false 36 | // --> Character 37 | // --> '.' 38 | // --> Integer 39 | // --> [\+\-]?[0-9]+ 40 | // --> Float 41 | // --> [\+\-]?([0-9]+ | [0-9]*\.[0-9]+ | [0-9]+\.[0-9]*)(e)? 42 | // --> String 43 | // --> ".*" 44 | // --> | | | | 45 | // --> | | | | 46 | // --> Vector\<\> 47 | // --> Set\<\> 48 | // --> Dictionary\<,\> 49 | // --> | | 50 | // --> | 51 | // --> Connection 52 | // --> Context 53 | // --> null | true | false | Connection | Context | Boolean | Character | Integer | Float | String | 54 | // Vector | Set | Dictionary 55 | // --> [a-zA-Z][a-zA-Z0-9_]* - 56 | // --> 57 | // --> (::)? 58 | // --> | | | 59 | // --> \?? 60 | // --> [:\?]{1} 61 | // --> | | 62 | // --> 63 | // --> (\s)? 64 | // --> \s( | ); 65 | // 66 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 67 | 68 | #include 69 | #include 70 | 71 | namespace Grammar { 72 | 73 | // Set of reserved words. 74 | extern std::set RESERVED_WORDS; 75 | 76 | // Grammar rule for . 77 | bool is_spaces(const std::string& str); 78 | 79 | // Grammar rule for . 80 | bool is_boolean_type(const std::string& str); 81 | 82 | // Grammar rule for . 83 | bool is_boolean_value(const std::string& str); 84 | 85 | // Grammar rule for . 86 | bool is_character_type(const std::string& str); 87 | 88 | // Grammar rule for . 89 | bool is_character_value(const std::string& str); 90 | 91 | // Grammar rule for . 92 | bool is_integer_type(const std::string& str); 93 | 94 | // Grammar rule for . 95 | bool is_integer_value(const std::string& str); 96 | 97 | // Grammar rule for . 98 | bool is_float_type(const std::string& str); 99 | 100 | // Grammar rule for . 101 | bool is_float_value(const std::string& str); 102 | 103 | // Grammar rule for . 104 | bool is_string_type(const std::string& str); 105 | 106 | // Grammar rule for . 107 | bool is_string_value(const std::string& str); 108 | 109 | // Grammar rule for . 110 | bool is_object_type(const std::string& str); 111 | 112 | // Grammar rule for . 113 | bool is_object_value(const std::string& str); 114 | 115 | // Grammar rule for . 116 | bool is_vector_type(const std::string& str); 117 | 118 | // Grammar rule for . 119 | bool is_set_type(const std::string& str); 120 | 121 | // Grammar rule for . 122 | bool is_dictionary_type(const std::string& str); 123 | 124 | // Grammar rule for . 125 | bool is_container_type(const std::string& str); 126 | 127 | // Grammar rule for . 128 | bool is_type(const std::string& str); 129 | 130 | // Grammar rule for . 131 | bool is_connection(const std::string& str); 132 | 133 | // Grammar rule for . 134 | bool is_context(const std::string& str); 135 | 136 | // Grammar rule for . 137 | bool is_reserved_word(const std::string& str); 138 | 139 | // Grammar rule for . 140 | bool is_identifier(const std::string& str); 141 | 142 | // Grammar rule for . 143 | bool is_namespace(const std::string& str); 144 | 145 | // Grammar rule for . 146 | bool is_variable(const std::string& str); 147 | 148 | // Grammar rule for . 149 | bool is_actor(const std::string& str); 150 | 151 | // Grammar rule for . 152 | bool is_unary_message(const std::string& str); 153 | 154 | // Grammar rule for . 155 | bool is_keyword_message_token(const std::string& str); 156 | 157 | // Grammar rule for . 158 | bool is_keyword_message_argument(const std::string& str); 159 | 160 | // Grammar rule for . 161 | bool is_keyword_message_part(const std::string& str); 162 | 163 | // Grammar rule for . 164 | bool is_keyword_message(const std::string& str); 165 | 166 | // Grammar rule for . 167 | bool is_statement(const std::string& str); 168 | 169 | } 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /src/instance.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KNUCKLEBALL_INSTANCE_H 27 | #define KNUCKLEBALL_INSTANCE_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class Instance : public std::enable_shared_from_this { 36 | protected: 37 | // Attributes: 38 | std::string _type; 39 | std::string _name; 40 | 41 | // Constructor: 42 | Instance(const std::string& type); 43 | public: 44 | // Virtual destructor: 45 | virtual ~Instance(); 46 | 47 | // Getter methods: 48 | std::string type() const; 49 | std::string name() const; 50 | 51 | // Pure virtual methods: 52 | virtual std::string representation() const = 0; 53 | virtual std::string receive(const std::string& message_name, const std::vector& arguments) = 0; 54 | }; 55 | 56 | class InstanceIsEqualToComparator { 57 | public: 58 | // Functor to compare two Instances. 59 | bool operator()(const std::shared_ptr& lhs, const std::shared_ptr& rhs) const; 60 | }; 61 | 62 | class InstanceIsLessThanComparator { 63 | public: 64 | // Functor to compare two Instances. 65 | bool operator()(const std::shared_ptr& lhs, const std::shared_ptr& rhs) const; 66 | }; 67 | 68 | class InstanceIsLessThanOrEqualToComparator { 69 | public: 70 | // Functor to compare two Instances. 71 | bool operator()(const std::shared_ptr& lhs, const std::shared_ptr& rhs) const; 72 | }; 73 | 74 | class InstanceIsGreaterThanComparator { 75 | public: 76 | // Functor to compare two Instances. 77 | bool operator()(const std::shared_ptr& lhs, const std::shared_ptr& rhs) const; 78 | }; 79 | 80 | class InstanceIsGreaterThanOrEqualToComparator { 81 | public: 82 | // Functor to compare two Instances. 83 | bool operator()(const std::shared_ptr& lhs, const std::shared_ptr& rhs) const; 84 | }; 85 | 86 | class BooleanInstance: public Instance { 87 | private: 88 | // Attributes: 89 | bool _value; 90 | 91 | // Operators: 92 | std::string op_get(const std::vector& arguments); 93 | std::string op_set(const std::vector& arguments); 94 | std::string op_isTrue(const std::vector& arguments); 95 | std::string op_isFalse(const std::vector& arguments); 96 | public: 97 | // Constructors: 98 | BooleanInstance(const std::string& value); 99 | BooleanInstance(const std::string& message_name, const std::vector& arguments); 100 | 101 | // Virtual destructor: 102 | virtual ~BooleanInstance(); 103 | 104 | // Getter method: 105 | bool value() const; 106 | 107 | // Implementation of pure virtual methods: 108 | virtual std::string representation() const; 109 | virtual std::string receive(const std::string& message_name, const std::vector& arguments); 110 | }; 111 | 112 | class CharacterInstance: public Instance { 113 | private: 114 | // Attributes: 115 | char _value; 116 | 117 | // Operators: 118 | std::string op_get(const std::vector& arguments); 119 | std::string op_set(const std::vector& arguments); 120 | std::string op_isAlphabetic(const std::vector& arguments); 121 | std::string op_isNumeric(const std::vector& arguments); 122 | std::string op_isAlphanumeric(const std::vector& arguments); 123 | std::string op_isSpace(const std::vector& arguments); 124 | std::string op_isEqualTo(const std::vector& arguments); 125 | std::string op_isLessThan(const std::vector& arguments); 126 | std::string op_isLessThanOrEqualTo(const std::vector& arguments); 127 | std::string op_isGreaterThan(const std::vector& arguments); 128 | std::string op_isGreaterThanOrEqualTo(const std::vector& arguments); 129 | public: 130 | // Constructors: 131 | CharacterInstance(const std::string& value); 132 | CharacterInstance(const std::string& message_name, const std::vector& arguments); 133 | 134 | // Virtual destructor: 135 | virtual ~CharacterInstance(); 136 | 137 | // Getter method: 138 | char value() const; 139 | 140 | // Implementation of pure virtual methods: 141 | virtual std::string representation() const; 142 | virtual std::string receive(const std::string& message_name, const std::vector& arguments); 143 | }; 144 | 145 | class IntegerInstance: public Instance { 146 | private: 147 | // Attributes: 148 | int _value; 149 | 150 | // Operators: 151 | std::string op_get(const std::vector& arguments); 152 | std::string op_set(const std::vector& arguments); 153 | std::string op_isEqualTo(const std::vector& arguments); 154 | std::string op_isLessThan(const std::vector& arguments); 155 | std::string op_isLessThanOrEqualTo(const std::vector& arguments); 156 | std::string op_isGreaterThan(const std::vector& arguments); 157 | std::string op_isGreaterThanOrEqualTo(const std::vector& arguments); 158 | std::string op_add(const std::vector& arguments); 159 | std::string op_subtract(const std::vector& arguments); 160 | std::string op_multiplyBy(const std::vector& arguments); 161 | std::string op_divideBy(const std::vector& arguments); 162 | public: 163 | // Constructors: 164 | IntegerInstance(int value); 165 | IntegerInstance(const std::string& value); 166 | IntegerInstance(const std::string& message_name, const std::vector& arguments); 167 | 168 | // Virtual destructor: 169 | virtual ~IntegerInstance(); 170 | 171 | // Getter method: 172 | int value() const; 173 | 174 | // Implementation of pure virtual methods: 175 | virtual std::string representation() const; 176 | virtual std::string receive(const std::string& message_name, const std::vector& arguments); 177 | }; 178 | 179 | class FloatInstance: public Instance { 180 | private: 181 | // Attributes: 182 | float _value; 183 | 184 | // Operators: 185 | std::string op_get(const std::vector& arguments); 186 | std::string op_set(const std::vector& arguments); 187 | std::string op_isEqualTo(const std::vector& arguments); 188 | std::string op_isLessThan(const std::vector& arguments); 189 | std::string op_isLessThanOrEqualTo(const std::vector& arguments); 190 | std::string op_isGreaterThan(const std::vector& arguments); 191 | std::string op_isGreaterThanOrEqualTo(const std::vector& arguments); 192 | std::string op_add(const std::vector& arguments); 193 | std::string op_subtract(const std::vector& arguments); 194 | std::string op_multiplyBy(const std::vector& arguments); 195 | std::string op_divideBy(const std::vector& arguments); 196 | public: 197 | // Constructors: 198 | FloatInstance(float value); 199 | FloatInstance(const std::string& value); 200 | FloatInstance(const std::string& message_name, const std::vector& arguments); 201 | 202 | // Virtual destructor: 203 | virtual ~FloatInstance(); 204 | 205 | // Getter method: 206 | float value() const; 207 | 208 | // Implementation of pure virtual methods: 209 | virtual std::string representation() const; 210 | virtual std::string receive(const std::string& message_name, const std::vector& arguments); 211 | }; 212 | 213 | class StringInstance: public Instance { 214 | private: 215 | // Attributes: 216 | std::string _value; 217 | 218 | // Operators: 219 | std::string op_get(const std::vector& arguments); 220 | std::string op_set(const std::vector& arguments); 221 | std::string op_isEmpty(const std::vector& arguments); 222 | std::string op_startsWith(const std::vector& arguments); 223 | std::string op_endsWith(const std::vector& arguments); 224 | std::string op_isLexicographicallyEqualTo(const std::vector& arguments); 225 | std::string op_isLexicographicallyLessThan(const std::vector& arguments); 226 | std::string op_isLexicographicallyLessThanOrEqualTo(const std::vector& arguments); 227 | std::string op_isLexicographicallyGreaterThan(const std::vector& arguments); 228 | std::string op_isLexicographicallyGreaterThanOrEqualTo(const std::vector& arguments); 229 | std::string op_length(const std::vector& arguments); 230 | std::string op_atIndex(const std::vector& arguments); 231 | std::string op_first(const std::vector& arguments); 232 | std::string op_last(const std::vector& arguments); 233 | std::string op_substringFromIndex(const std::vector& arguments); 234 | std::string op_substringFromIndex_toIndex(const std::vector& arguments); 235 | std::string op_pushBack(const std::vector& arguments); 236 | std::string op_pushFront(const std::vector& arguments); 237 | std::string op_popBack(const std::vector& arguments); 238 | std::string op_popFront(const std::vector& arguments); 239 | std::string op_popAtIndex(const std::vector& arguments); 240 | std::string op_concatenate(const std::vector& arguments); 241 | std::string op_insert_beforeIndex(const std::vector& arguments); 242 | std::string op_eraseFromIndex(const std::vector& arguments); 243 | std::string op_eraseFromIndex_toIndex(const std::vector& arguments); 244 | std::string op_clear(const std::vector& arguments); 245 | public: 246 | // Constructors: 247 | StringInstance(const std::string& value); 248 | StringInstance(const std::string& message_name, const std::vector& arguments); 249 | 250 | // Virtual destructor: 251 | virtual ~StringInstance(); 252 | 253 | // Getter method: 254 | std::string value() const; 255 | 256 | // Implementation of pure virtual methods: 257 | virtual std::string representation() const; 258 | virtual std::string receive(const std::string& message_name, const std::vector& arguments); 259 | }; 260 | 261 | class VectorInstance: public Instance { 262 | private: 263 | // Attributes: 264 | std::string _element_type; 265 | std::vector> _value; 266 | 267 | // Operators: 268 | std::string op_get(const std::vector& arguments); 269 | std::string op_isEmpty(const std::vector& arguments); 270 | std::string op_contains(const std::vector& arguments); 271 | std::string op_contains_fromIndex(const std::vector& arguments); 272 | std::string op_count(const std::vector& arguments); 273 | std::string op_atIndex(const std::vector& arguments); 274 | std::string op_firstIndexOf(const std::vector& arguments); 275 | std::string op_firstIndexOf_fromIndex(const std::vector& arguments); 276 | std::string op_allIndexesOf(const std::vector& arguments); 277 | std::string op_size(const std::vector& arguments); 278 | std::string op_first(const std::vector& arguments); 279 | std::string op_last(const std::vector& arguments); 280 | std::string op_sliceFromIndex(const std::vector& arguments); 281 | std::string op_sliceFromIndex_toIndex(const std::vector& arguments); 282 | std::string op_pushBack(const std::vector& arguments); 283 | std::string op_pushFront(const std::vector& arguments); 284 | std::string op_popBack(const std::vector& arguments); 285 | std::string op_popFront(const std::vector& arguments); 286 | std::string op_popAtIndex(const std::vector& arguments); 287 | std::string op_insert_beforeIndex(const std::vector& arguments); 288 | std::string op_eraseFromIndex(const std::vector& arguments); 289 | std::string op_eraseFromIndex_toIndex(const std::vector& arguments); 290 | std::string op_removeFirst(const std::vector& arguments); 291 | std::string op_removeFirst_fromIndex(const std::vector& arguments); 292 | std::string op_removeAll(const std::vector& arguments); 293 | std::string op_replaceFirst_with(const std::vector& arguments); 294 | std::string op_replaceFirst_fromIndex_with(const std::vector& arguments); 295 | std::string op_replaceAll_with(const std::vector& arguments); 296 | std::string op_sort(const std::vector& arguments); 297 | std::string op_reverse(const std::vector& arguments); 298 | std::string op_clear(const std::vector& arguments); 299 | public: 300 | // Constructor: 301 | VectorInstance(const std::string& element_type, const std::string& message_name, 302 | const std::vector& arguments); 303 | 304 | // Virtual destructor: 305 | virtual ~VectorInstance(); 306 | 307 | // Implementation of pure virtual methods: 308 | virtual std::string representation() const; 309 | virtual std::string receive(const std::string& message_name, const std::vector& arguments); 310 | }; 311 | 312 | class SetInstance: public Instance { 313 | private: 314 | // Attributes: 315 | std::string _element_type; 316 | std::set, InstanceIsLessThanComparator> _value; 317 | 318 | // Operators: 319 | std::string op_get(const std::vector& arguments); 320 | std::string op_isEmpty(const std::vector& arguments); 321 | std::string op_contains(const std::vector& arguments); 322 | std::string op_size(const std::vector& arguments); 323 | std::string op_add(const std::vector& arguments); 324 | std::string op_remove(const std::vector& arguments); 325 | std::string op_clear(const std::vector& arguments); 326 | public: 327 | // Constructor: 328 | SetInstance(const std::string& element_type, const std::string& message_name, 329 | const std::vector& arguments); 330 | 331 | // Virtual destructor: 332 | virtual ~SetInstance(); 333 | 334 | // Implementation of pure virtual methods: 335 | virtual std::string representation() const; 336 | virtual std::string receive(const std::string& message_name, const std::vector& arguments); 337 | }; 338 | 339 | class DictionaryInstance: public Instance { 340 | private: 341 | // Attributes: 342 | std::string _key_type, _value_type; 343 | std::map, std::shared_ptr, InstanceIsLessThanComparator> _value; 344 | 345 | // Operators: 346 | std::string op_get(const std::vector& arguments); 347 | std::string op_isEmpty(const std::vector& arguments); 348 | std::string op_containsKey(const std::vector& arguments); 349 | std::string op_size(const std::vector& arguments); 350 | std::string op_keys(const std::vector& arguments); 351 | std::string op_values(const std::vector& arguments); 352 | std::string op_getValueForKey(const std::vector& arguments); 353 | std::string op_associateValue_withKey(const std::vector& arguments); 354 | std::string op_removeKey(const std::vector& arguments); 355 | std::string op_clear(const std::vector& arguments); 356 | public: 357 | // Constructor: 358 | DictionaryInstance(const std::string& key_type, const std::string& value_type, const std::string& message_name, 359 | const std::vector& arguments); 360 | 361 | // Virtual destructor: 362 | virtual ~DictionaryInstance(); 363 | 364 | // Implementation of pure virtual methods: 365 | virtual std::string representation() const; 366 | virtual std::string receive(const std::string& message_name, const std::vector& arguments); 367 | }; 368 | 369 | #endif 370 | -------------------------------------------------------------------------------- /src/knuckleball.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #include "context.h" 36 | #include "server.h" 37 | 38 | #define VERSION "0.1.0" 39 | 40 | int main(int argc, char* argv[]) { 41 | boost::program_options::options_description description("Options"); 42 | description.add_options() 43 | ("help,h", "print usage message") 44 | ("quiet,q", "quiet mode") 45 | ("bind", boost::program_options::value()->default_value("0.0.0.0"), "server ip") 46 | ("port,p", boost::program_options::value()->required(), "server port number") 47 | ("password", boost::program_options::value()->default_value(""), "server password") 48 | ("logfile", boost::program_options::value()->default_value(""), "log file name") 49 | ("floatprecision", boost::program_options::value()->default_value(3), 50 | "decimal precision to be used to format floating-point values") 51 | ("floatcomparisontolerance", boost::program_options::value()->default_value(0.0000001), 52 | "tolerance to be used to compare floating-point values"); 53 | boost::program_options::variables_map vmap; 54 | try { 55 | boost::program_options::store(boost::program_options::parse_command_line(argc, argv, description), vmap); 56 | if (vmap.count("help")) { 57 | std::cout << description << std::endl; 58 | return EXIT_SUCCESS; 59 | } 60 | boost::program_options::notify(vmap); 61 | } 62 | catch(std::exception& exception) { 63 | std::cerr << exception.what() << std::endl; 64 | return EXIT_FAILURE; 65 | } 66 | int pid = int(getpid()); 67 | std::cout << "Running Knuckleball " << VERSION << std::endl; 68 | std::cout << "PID: " << pid << std::endl; 69 | std::cout << std::endl; 70 | Context::get_instance(vmap["logfile"].as(), vmap["floatprecision"].as(), 71 | vmap["floatcomparisontolerance"].as(), vmap.count("quiet") > 0 ? true : false); 72 | Server::get_instance(vmap["bind"].as(), vmap["port"].as(), 73 | vmap["password"].as())->run(); 74 | return EXIT_FAILURE; 75 | } 76 | -------------------------------------------------------------------------------- /src/parser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "exceptions.h" 27 | #include "grammar.h" 28 | #include "parser.h" 29 | #include "str_utils.h" 30 | 31 | Parser::Parser(const std::string& input) { 32 | if (!Grammar::is_statement(input)) 33 | throw EXC_INVALID_STATEMENT; 34 | int i = 0; 35 | std::string trimmed_input = str_utils::trim(input); 36 | trimmed_input = str_utils::rtrim(trimmed_input.substr(0, int(trimmed_input.size()) - 1)); 37 | while (!str_utils::is_space(trimmed_input[i]) || !Grammar::is_actor(trimmed_input.substr(0, i))) 38 | i++; 39 | _actor = trimmed_input.substr(0, i); 40 | std::string message = str_utils::ltrim(trimmed_input.substr(i + 1)); 41 | if (Grammar::is_unary_message(message)) 42 | _message_name = message; 43 | else { 44 | int j = 0, k = 0; 45 | while (j < int(message.size())) { 46 | while (message[k] != ':' && message[k] != '?') 47 | k++; 48 | _message_name += message.substr(j, ++k - j); 49 | while (str_utils::is_space(message[k])) 50 | k++; 51 | j = k; 52 | while (k < int(message.size()) && 53 | (!str_utils::is_space(message[k]) || !Grammar::is_keyword_message_argument(message.substr(j, k - j)))) 54 | k++; 55 | _arguments.push_back(message.substr(j, k - j)); 56 | while (k < int(message.size()) && str_utils::is_space(message[k])) 57 | k++; 58 | j = k; 59 | } 60 | } 61 | } 62 | 63 | std::string Parser::actor() const { 64 | return _actor; 65 | } 66 | 67 | std::string Parser::message_name() const { 68 | return _message_name; 69 | } 70 | 71 | std::vector Parser::arguments() const { 72 | return _arguments; 73 | } 74 | -------------------------------------------------------------------------------- /src/parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KNUCKLEBALL_PARSER_H 27 | #define KNUCKLEBALL_PARSER_H 28 | 29 | #include 30 | #include 31 | 32 | class Parser { 33 | private: 34 | // Attributes: 35 | std::string _actor; 36 | std::string _message_name; 37 | std::vector _arguments; 38 | public: 39 | // Parse the input string and construct an instance or throw an exception. 40 | Parser(const std::string& input); 41 | 42 | // Getter methods: 43 | std::string actor() const; 44 | std::string message_name() const; 45 | std::vector arguments() const; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/server.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | #include "context.h" 30 | #include "exceptions.h" 31 | #include "grammar.h" 32 | #include "instance.h" 33 | #include "server.h" 34 | #include "str_utils.h" 35 | 36 | //////////////////////////////////////////////////////// Server //////////////////////////////////////////////////////// 37 | 38 | // Initialize the singleton instance. 39 | Server* Server::_instance = NULL; 40 | 41 | Server* Server::get_instance() { 42 | return _instance; 43 | } 44 | 45 | Server* Server::get_instance(const std::string& ip, int port, const std::string& password) { 46 | delete _instance; 47 | _instance = new Server(ip, port, password); 48 | return _instance; 49 | } 50 | 51 | Server::Server(const std::string& ip, int port, const std::string& password) : 52 | _password(password), 53 | _endpoint(boost::asio::ip::address::from_string(ip), port), 54 | _acceptor(_io_service, _endpoint), 55 | _socket(_io_service) { 56 | } 57 | 58 | Server::~Server() { 59 | _instance = NULL; 60 | } 61 | 62 | std::string Server::get_password() { 63 | return _password; 64 | } 65 | 66 | void Server::do_accept() { 67 | _acceptor.async_accept(_socket, 68 | [this](const boost::system::error_code& error_code) { 69 | if (!error_code) 70 | handle_accept(); 71 | } 72 | ); 73 | } 74 | 75 | void Server::handle_accept() { 76 | std::make_shared(std::move(_socket))->do_read(); 77 | do_accept(); 78 | } 79 | 80 | void Server::run() { 81 | do_accept(); 82 | _io_service.run(); 83 | } 84 | 85 | /////////////////////////////////////////////////////// Session //////////////////////////////////////////////////////// 86 | 87 | Session::Session(boost::asio::ip::tcp::socket socket) : _is_connected(true), _socket(std::move(socket)) { 88 | _is_authenticated = (Server::get_instance()->get_password() == ""); 89 | } 90 | 91 | std::string Session::receive(const std::string& message_name, const std::vector& arguments) { 92 | if (message_name == "close") { 93 | _is_connected = false; 94 | return "null"; 95 | } 96 | if (message_name == "authenticateWithPassword:") { 97 | if (arguments.size() != 1) 98 | throw EXC_WRONG_NUMBER_OF_ARGUMENTS; 99 | if (!Grammar::is_string_value(arguments[0])) 100 | throw EXC_INVALID_ARGUMENT; 101 | if (StringInstance(arguments[0]).value() == Server::get_instance()->get_password()) { 102 | _is_authenticated = true; 103 | return "null"; 104 | } 105 | throw EXC_WRONG_PASSWORD; 106 | } 107 | throw EXC_INVALID_MESSAGE; 108 | } 109 | 110 | void Session::do_read() { 111 | auto self(shared_from_this()); 112 | boost::asio::async_read_until(_socket, _streambuf, '\n', 113 | [this, self](const boost::system::error_code& error_code, std::size_t bytes_transferred) { 114 | if (!error_code) { 115 | std::istream istream(&_streambuf); 116 | std::string input; 117 | std::getline(istream, input); 118 | std::string actor; 119 | try { 120 | Parser parser(input); 121 | actor = parser.actor(); 122 | } 123 | catch (...) { 124 | } 125 | if (_is_authenticated || Grammar::is_connection(actor)) { 126 | std::string output = Context::get_instance()->execute(input, self); 127 | if (_is_connected) 128 | do_write(output); 129 | } 130 | else 131 | do_write(EXC_NOT_AUTHENTICATED); 132 | } 133 | } 134 | ); 135 | } 136 | 137 | void Session::do_write(const std::string& response) { 138 | auto self(shared_from_this()); 139 | boost::asio::async_write(_socket, boost::asio::buffer(response + "\n"), 140 | [this, self](const boost::system::error_code& error_code, std::size_t bytes_transferred) { 141 | if (!error_code) 142 | do_read(); 143 | } 144 | ); 145 | } 146 | -------------------------------------------------------------------------------- /src/server.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KNUCKLEBALL_SERVER_H 27 | #define KNUCKLEBALL_SERVER_H 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | class Server { 36 | private: 37 | // Singleton instance: 38 | static Server *_instance; 39 | 40 | // Attributes: 41 | std::string _password; 42 | boost::asio::io_service _io_service; 43 | boost::asio::ip::tcp::endpoint _endpoint; 44 | boost::asio::ip::tcp::acceptor _acceptor; 45 | boost::asio::ip::tcp::socket _socket; 46 | 47 | // Constructor: 48 | Server(const std::string& ip, int port, const std::string& password); 49 | 50 | // Asynchronously accept a new connection. 51 | void do_accept(); 52 | void handle_accept(); 53 | 54 | // Delete copy constructor and assignment operator. 55 | Server(const Server& other) = delete; 56 | Server& operator=(const Server& other) = delete; 57 | public: 58 | // Singleton getter: 59 | static Server* get_instance(); 60 | static Server* get_instance(const std::string& ip, int port, const std::string& password); 61 | 62 | // Destructor: 63 | ~Server(); 64 | 65 | // Getter methods: 66 | std::string get_password(); 67 | 68 | // Loop: 69 | void run(); 70 | }; 71 | 72 | class Session : public std::enable_shared_from_this { 73 | private: 74 | // Attributes: 75 | bool _is_connected; 76 | bool _is_authenticated; 77 | boost::asio::streambuf _streambuf; 78 | boost::asio::ip::tcp::socket _socket; 79 | 80 | // Delete copy constructor and assignment operator. 81 | Session(const Session& other) = delete; 82 | Session& operator=(const Session& other) = delete; 83 | public: 84 | // Constructor: 85 | Session(boost::asio::ip::tcp::socket socket); 86 | 87 | // Receive message and return a string. 88 | std::string receive(const std::string& message_name, const std::vector& arguments); 89 | 90 | // Asynchronously read input from socket and process it. 91 | void do_read(); 92 | 93 | // Asynchronously write response to socket. 94 | void do_write(const std::string& response); 95 | }; 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/str_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include 27 | 28 | #include "str_utils.h" 29 | 30 | namespace str_utils { 31 | 32 | std::string ltrim(const std::string& str) { 33 | int i = 0; 34 | while (i < int(str.size()) && isspace(str[i])) 35 | i++; 36 | return str.substr(i); 37 | } 38 | 39 | std::string rtrim(const std::string& str) { 40 | int i = int(str.size()) - 1; 41 | while (i >= 0 && isspace(str[i])) 42 | i--; 43 | return str.substr(0, i + 1); 44 | } 45 | 46 | std::string trim(const std::string& str) { 47 | return rtrim(ltrim(str)); 48 | } 49 | 50 | std::string escape(const std::string& str, char c) { 51 | std::string escaped_str; 52 | for (int i = 0; i < int(str.size()); i++) { 53 | if (str[i] == c) 54 | escaped_str += "\\"; 55 | escaped_str += std::string(1, str[i]); 56 | } 57 | return escaped_str; 58 | } 59 | 60 | std::string unescape(const std::string& str, char c) { 61 | std::string unescaped_str; 62 | for (int i = 0; i < int(str.size()); i++) { 63 | if (i < int(str.size()) - 1 && str[i] == '\\' && str[i + 1] == c) 64 | continue; 65 | unescaped_str += std::string(1, str[i]); 66 | } 67 | return unescaped_str; 68 | } 69 | 70 | bool is_space(char c) { 71 | return isspace(c); 72 | } 73 | 74 | bool is_alpha(char c) { 75 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); 76 | } 77 | 78 | bool is_numeric(char c) { 79 | return (c >= '0' && c <= '9'); 80 | } 81 | 82 | bool is_alphanumeric(char c) { 83 | return is_alpha(c) || is_numeric(c); 84 | } 85 | 86 | bool starts_with(const std::string& str, const std::string& prefix) { 87 | if (str.size() < prefix.size()) 88 | return false; 89 | for (int i = 0; i < int(prefix.size()); i++) 90 | if (str[i] != prefix[i]) 91 | return false; 92 | return true; 93 | } 94 | 95 | bool ends_with(const std::string& str, const std::string& suffix) { 96 | if (str.size() < suffix.size()) 97 | return false; 98 | for (int i = 0; i < int(suffix.size()); i++) 99 | if (str[int(str.size()) - i - 1] != suffix[int(suffix.size()) - i - 1]) 100 | return false; 101 | return true; 102 | } 103 | 104 | std::string remove_spaces(const std::string& str) { 105 | std::string str_without_spaces; 106 | for (int i = 0; i < int(str.size()); i++) { 107 | if (is_space(str[i])) 108 | continue; 109 | str_without_spaces += std::string(1, str[i]); 110 | } 111 | return str_without_spaces; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/str_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef KNUCKLEBALL_STR_UTILS_H 27 | #define KNUCKLEBALL_STR_UTILS_H 28 | 29 | #include 30 | 31 | namespace str_utils { 32 | 33 | // Return the string trimmed from the left. 34 | std::string ltrim(const std::string& str); 35 | 36 | // Return the string trimmed from the right. 37 | std::string rtrim(const std::string& str); 38 | 39 | // Return the string trimmed from both ends. 40 | std::string trim(const std::string& str); 41 | 42 | // Return the string with character c escaped. 43 | std::string escape(const std::string& str, char c); 44 | 45 | // Return the string with character c unescaped. 46 | std::string unescape(const std::string& str, char c); 47 | 48 | // Check whether c is a space character. 49 | bool is_space(char c); 50 | 51 | // Check whether c is an alphabetic character. 52 | bool is_alpha(char c); 53 | 54 | // Check whether c is a numeric character. 55 | bool is_numeric(char c); 56 | 57 | // Check whether c is an alphabetic or numeric character. 58 | bool is_alphanumeric(char c); 59 | 60 | // Check whether the string is prefixed by prefix. 61 | bool starts_with(const std::string& str, const std::string& prefix); 62 | 63 | // Check whether the string is suffixed by suffix. 64 | bool ends_with(const std::string& str, const std::string& suffix); 65 | 66 | // Return the string with its spaces removed. 67 | std::string remove_spaces(const std::string& str); 68 | 69 | } 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /tests/grammar_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "gtest/gtest.h" 27 | 28 | #include "grammar.h" 29 | 30 | TEST(Grammar, is_spaces) { 31 | EXPECT_TRUE(Grammar::is_spaces("")); 32 | EXPECT_TRUE(Grammar::is_spaces(" ")); 33 | EXPECT_TRUE(Grammar::is_spaces("\n")); 34 | EXPECT_TRUE(Grammar::is_spaces("\t")); 35 | } 36 | 37 | TEST(Grammar, is_not_spaces) { 38 | EXPECT_FALSE(Grammar::is_spaces("knuckleball")); 39 | EXPECT_FALSE(Grammar::is_spaces(" knuckleball")); 40 | EXPECT_FALSE(Grammar::is_spaces("knuckleball ")); 41 | } 42 | 43 | TEST(Grammar, is_boolean_type) { 44 | EXPECT_TRUE(Grammar::is_boolean_type("Boolean")); 45 | } 46 | 47 | TEST(Grammar, is_not_boolean_type) { 48 | EXPECT_FALSE(Grammar::is_boolean_type("")); 49 | EXPECT_FALSE(Grammar::is_boolean_type("boolean")); 50 | EXPECT_FALSE(Grammar::is_boolean_type("BOOLEAN")); 51 | EXPECT_FALSE(Grammar::is_boolean_type(" Boolean")); 52 | EXPECT_FALSE(Grammar::is_boolean_type("Boolean ")); 53 | } 54 | 55 | TEST(Grammar, is_boolean_value) { 56 | EXPECT_TRUE(Grammar::is_boolean_value("true")); 57 | EXPECT_TRUE(Grammar::is_boolean_value("false")); 58 | } 59 | 60 | TEST(Grammar, is_not_boolean_value) { 61 | EXPECT_FALSE(Grammar::is_boolean_value("")); 62 | EXPECT_FALSE(Grammar::is_boolean_value("1")); 63 | EXPECT_FALSE(Grammar::is_boolean_value("0")); 64 | EXPECT_FALSE(Grammar::is_boolean_value("TRUE")); 65 | EXPECT_FALSE(Grammar::is_boolean_value("FALSE")); 66 | EXPECT_FALSE(Grammar::is_boolean_value("True")); 67 | EXPECT_FALSE(Grammar::is_boolean_value("False")); 68 | EXPECT_FALSE(Grammar::is_boolean_value(" true")); 69 | EXPECT_FALSE(Grammar::is_boolean_value("false ")); 70 | } 71 | 72 | TEST(Grammar, is_character_type) { 73 | EXPECT_TRUE(Grammar::is_character_type("Character")); 74 | } 75 | 76 | TEST(Grammar, is_not_character_type) { 77 | EXPECT_FALSE(Grammar::is_character_type("")); 78 | EXPECT_FALSE(Grammar::is_character_type("character")); 79 | EXPECT_FALSE(Grammar::is_character_type("CHARACTER")); 80 | EXPECT_FALSE(Grammar::is_character_type(" Character")); 81 | EXPECT_FALSE(Grammar::is_character_type("Character ")); 82 | } 83 | 84 | TEST(Grammar, is_character_value) { 85 | EXPECT_TRUE(Grammar::is_character_value("'a'")); 86 | EXPECT_TRUE(Grammar::is_character_value("'A'")); 87 | EXPECT_TRUE(Grammar::is_character_value("'0'")); 88 | EXPECT_TRUE(Grammar::is_character_value("'#'")); 89 | EXPECT_TRUE(Grammar::is_character_value("' '")); 90 | EXPECT_TRUE(Grammar::is_character_value("'\''")); 91 | } 92 | 93 | TEST(Grammar, is_not_character_value) { 94 | EXPECT_FALSE(Grammar::is_character_value("")); 95 | EXPECT_FALSE(Grammar::is_character_value("''")); 96 | EXPECT_FALSE(Grammar::is_character_value("'aa'")); 97 | EXPECT_FALSE(Grammar::is_character_value("'a' ")); 98 | EXPECT_FALSE(Grammar::is_character_value(" 'a'")); 99 | } 100 | 101 | TEST(Grammar, is_integer_type) { 102 | EXPECT_TRUE(Grammar::is_integer_type("Integer")); 103 | } 104 | 105 | TEST(Grammar, is_not_integer_type) { 106 | EXPECT_FALSE(Grammar::is_integer_type("")); 107 | EXPECT_FALSE(Grammar::is_integer_type("integer")); 108 | EXPECT_FALSE(Grammar::is_integer_type("INTEGER")); 109 | EXPECT_FALSE(Grammar::is_integer_type(" Integer")); 110 | EXPECT_FALSE(Grammar::is_integer_type("Integer ")); 111 | } 112 | 113 | TEST(Grammar, is_integer_value) { 114 | EXPECT_TRUE(Grammar::is_integer_value("0")); 115 | EXPECT_TRUE(Grammar::is_integer_value("+0")); 116 | EXPECT_TRUE(Grammar::is_integer_value("-0")); 117 | EXPECT_TRUE(Grammar::is_integer_value("42")); 118 | EXPECT_TRUE(Grammar::is_integer_value("+42")); 119 | EXPECT_TRUE(Grammar::is_integer_value("-42")); 120 | } 121 | 122 | TEST(Grammar, is_not_integer_value) { 123 | EXPECT_FALSE(Grammar::is_integer_value("")); 124 | EXPECT_FALSE(Grammar::is_integer_value("+")); 125 | EXPECT_FALSE(Grammar::is_integer_value("-")); 126 | EXPECT_FALSE(Grammar::is_integer_value("42.0")); 127 | EXPECT_FALSE(Grammar::is_integer_value("42e5")); 128 | EXPECT_FALSE(Grammar::is_integer_value(" 42")); 129 | EXPECT_FALSE(Grammar::is_integer_value("42 ")); 130 | } 131 | 132 | TEST(Grammar, is_float_type) { 133 | EXPECT_TRUE(Grammar::is_float_type("Float")); 134 | } 135 | 136 | TEST(Grammar, is_not_float_type) { 137 | EXPECT_FALSE(Grammar::is_float_type("")); 138 | EXPECT_FALSE(Grammar::is_float_type("float")); 139 | EXPECT_FALSE(Grammar::is_float_type("FLOAT")); 140 | EXPECT_FALSE(Grammar::is_float_type(" Float")); 141 | EXPECT_FALSE(Grammar::is_float_type("Float ")); 142 | } 143 | 144 | TEST(Grammar, is_float_value) { 145 | EXPECT_TRUE(Grammar::is_float_value("0")); 146 | EXPECT_TRUE(Grammar::is_float_value("+0")); 147 | EXPECT_TRUE(Grammar::is_float_value("-0")); 148 | EXPECT_TRUE(Grammar::is_float_value("42")); 149 | EXPECT_TRUE(Grammar::is_float_value("+42")); 150 | EXPECT_TRUE(Grammar::is_float_value("-42")); 151 | EXPECT_TRUE(Grammar::is_float_value("42.")); 152 | EXPECT_TRUE(Grammar::is_float_value("+42.")); 153 | EXPECT_TRUE(Grammar::is_float_value("-42.")); 154 | EXPECT_TRUE(Grammar::is_float_value(".42")); 155 | EXPECT_TRUE(Grammar::is_float_value("+.42")); 156 | EXPECT_TRUE(Grammar::is_float_value("-.42")); 157 | EXPECT_TRUE(Grammar::is_float_value("42.0")); 158 | EXPECT_TRUE(Grammar::is_float_value("+42.0")); 159 | EXPECT_TRUE(Grammar::is_float_value("-42.0")); 160 | EXPECT_TRUE(Grammar::is_float_value("42e1")); 161 | EXPECT_TRUE(Grammar::is_float_value("42e+1")); 162 | EXPECT_TRUE(Grammar::is_float_value("42e-1")); 163 | EXPECT_TRUE(Grammar::is_float_value("42.0e1")); 164 | EXPECT_TRUE(Grammar::is_float_value("42.0e+1")); 165 | EXPECT_TRUE(Grammar::is_float_value("42.0e-1")); 166 | EXPECT_TRUE(Grammar::is_float_value("42.e1")); 167 | EXPECT_TRUE(Grammar::is_float_value("42.e+1")); 168 | EXPECT_TRUE(Grammar::is_float_value("42.e-1")); 169 | EXPECT_TRUE(Grammar::is_float_value(".42e1")); 170 | EXPECT_TRUE(Grammar::is_float_value(".42e+1")); 171 | EXPECT_TRUE(Grammar::is_float_value(".42e-1")); 172 | } 173 | 174 | TEST(Grammar, is_not_float_value) { 175 | EXPECT_FALSE(Grammar::is_float_value("")); 176 | EXPECT_FALSE(Grammar::is_float_value("+")); 177 | EXPECT_FALSE(Grammar::is_float_value("-")); 178 | EXPECT_FALSE(Grammar::is_float_value(".")); 179 | EXPECT_FALSE(Grammar::is_float_value("+.")); 180 | EXPECT_FALSE(Grammar::is_float_value("-.")); 181 | EXPECT_FALSE(Grammar::is_float_value("42..0")); 182 | EXPECT_FALSE(Grammar::is_float_value("e1")); 183 | EXPECT_FALSE(Grammar::is_float_value("+e1")); 184 | EXPECT_FALSE(Grammar::is_float_value("-e1")); 185 | EXPECT_FALSE(Grammar::is_float_value(".e1")); 186 | EXPECT_FALSE(Grammar::is_float_value("+.e1")); 187 | EXPECT_FALSE(Grammar::is_float_value("-.e1")); 188 | EXPECT_FALSE(Grammar::is_float_value("42e1.0")); 189 | EXPECT_FALSE(Grammar::is_float_value(" 42.0")); 190 | EXPECT_FALSE(Grammar::is_float_value("42.0 ")); 191 | } 192 | 193 | TEST(Grammar, is_string_type) { 194 | EXPECT_TRUE(Grammar::is_string_type("String")); 195 | } 196 | 197 | TEST(Grammar, is_not_string_type) { 198 | EXPECT_FALSE(Grammar::is_string_type("")); 199 | EXPECT_FALSE(Grammar::is_string_type("string")); 200 | EXPECT_FALSE(Grammar::is_string_type("STRING")); 201 | EXPECT_FALSE(Grammar::is_string_type(" String")); 202 | EXPECT_FALSE(Grammar::is_string_type("String ")); 203 | } 204 | 205 | TEST(Grammar, is_string_value) { 206 | EXPECT_TRUE(Grammar::is_string_value("\"\"")); 207 | EXPECT_TRUE(Grammar::is_string_value("\"knuckleball\"")); 208 | EXPECT_TRUE(Grammar::is_string_value("\"knuckle\\\"ball\"")); 209 | EXPECT_TRUE(Grammar::is_string_value("\"\\\\\"")); 210 | } 211 | 212 | TEST(Grammar, is_not_string_value) { 213 | EXPECT_FALSE(Grammar::is_string_value("")); 214 | EXPECT_FALSE(Grammar::is_string_value("\"")); 215 | EXPECT_FALSE(Grammar::is_string_value("\"\"\"")); 216 | EXPECT_FALSE(Grammar::is_string_value("\"\"\"\"")); 217 | EXPECT_FALSE(Grammar::is_string_value("\"\\\"")); 218 | EXPECT_FALSE(Grammar::is_string_value("\"knuckle\"ball\"")); 219 | EXPECT_FALSE(Grammar::is_string_value("\"knuckleball")); 220 | EXPECT_FALSE(Grammar::is_string_value("knuckleball\"")); 221 | EXPECT_FALSE(Grammar::is_string_value(" \"\"")); 222 | EXPECT_FALSE(Grammar::is_string_value("\"\" ")); 223 | } 224 | 225 | TEST(Grammar, is_object_type) { 226 | EXPECT_TRUE(Grammar::is_object_type("Boolean")); 227 | EXPECT_TRUE(Grammar::is_object_type("Character")); 228 | EXPECT_TRUE(Grammar::is_object_type("Integer")); 229 | EXPECT_TRUE(Grammar::is_object_type("Float")); 230 | EXPECT_TRUE(Grammar::is_object_type("String")); 231 | } 232 | 233 | TEST(Grammar, is_not_object_type) { 234 | EXPECT_FALSE(Grammar::is_object_type("Vector")); 235 | EXPECT_FALSE(Grammar::is_object_type("Vector")); 236 | EXPECT_FALSE(Grammar::is_object_type("Set")); 237 | EXPECT_FALSE(Grammar::is_object_type("Set")); 238 | EXPECT_FALSE(Grammar::is_object_type("Dictionary")); 239 | EXPECT_FALSE(Grammar::is_object_type("Dictionary")); 240 | } 241 | 242 | TEST(Grammar, is_object_value) { 243 | EXPECT_TRUE(Grammar::is_object_value("true")); 244 | EXPECT_TRUE(Grammar::is_object_value("false")); 245 | EXPECT_TRUE(Grammar::is_object_value("'a'")); 246 | EXPECT_TRUE(Grammar::is_object_value("42")); 247 | EXPECT_TRUE(Grammar::is_object_value("42e5")); 248 | EXPECT_TRUE(Grammar::is_object_value("\"knuckleball\"")); 249 | } 250 | 251 | TEST(Grammar, is_not_object_value) { 252 | EXPECT_FALSE(Grammar::is_object_value("")); 253 | EXPECT_FALSE(Grammar::is_object_value("prices")); 254 | EXPECT_FALSE(Grammar::is_object_value("isEmpty?")); 255 | EXPECT_FALSE(Grammar::is_object_value(" 42")); 256 | EXPECT_FALSE(Grammar::is_object_value("42 ")); 257 | } 258 | 259 | TEST(Grammar, is_vector_type) { 260 | EXPECT_TRUE(Grammar::is_vector_type("Vector")); 261 | EXPECT_TRUE(Grammar::is_vector_type("Vector< Character>")); 262 | EXPECT_TRUE(Grammar::is_vector_type("Vector")); 263 | EXPECT_TRUE(Grammar::is_vector_type("Vector< String >")); 264 | } 265 | 266 | TEST(Grammar, is_not_vector_type) { 267 | EXPECT_FALSE(Grammar::is_vector_type("")); 268 | EXPECT_FALSE(Grammar::is_vector_type("Vector")); 269 | EXPECT_FALSE(Grammar::is_vector_type("Vector ")); 270 | EXPECT_FALSE(Grammar::is_vector_type("Vector>")); 271 | EXPECT_FALSE(Grammar::is_vector_type("Vector")); 272 | EXPECT_FALSE(Grammar::is_vector_type("vector")); 273 | EXPECT_FALSE(Grammar::is_vector_type("VECTOR")); 274 | EXPECT_FALSE(Grammar::is_vector_type(" Vector")); 275 | EXPECT_FALSE(Grammar::is_vector_type("Vector ")); 276 | } 277 | 278 | TEST(Grammar, is_set_type) { 279 | EXPECT_TRUE(Grammar::is_set_type("Set")); 280 | EXPECT_TRUE(Grammar::is_set_type("Set< Character>")); 281 | EXPECT_TRUE(Grammar::is_set_type("Set")); 282 | EXPECT_TRUE(Grammar::is_set_type("Set< String >")); 283 | } 284 | 285 | TEST(Grammar, is_not_set_type) { 286 | EXPECT_FALSE(Grammar::is_set_type("")); 287 | EXPECT_FALSE(Grammar::is_set_type("Set")); 288 | EXPECT_FALSE(Grammar::is_set_type("Set ")); 289 | EXPECT_FALSE(Grammar::is_set_type("Set>")); 290 | EXPECT_FALSE(Grammar::is_set_type("Set")); 291 | EXPECT_FALSE(Grammar::is_set_type("set")); 292 | EXPECT_FALSE(Grammar::is_set_type("SET")); 293 | EXPECT_FALSE(Grammar::is_set_type(" Set")); 294 | EXPECT_FALSE(Grammar::is_set_type("Set ")); 295 | } 296 | 297 | TEST(Grammar, is_dictionary_type) { 298 | EXPECT_TRUE(Grammar::is_dictionary_type("Dictionary")); 299 | EXPECT_TRUE(Grammar::is_dictionary_type("Dictionary< String, Integer>")); 300 | EXPECT_TRUE(Grammar::is_dictionary_type("Dictionary")); 301 | EXPECT_TRUE(Grammar::is_dictionary_type("Dictionary< String , String >")); 302 | } 303 | 304 | TEST(Grammar, is_not_dictionary_type) { 305 | EXPECT_FALSE(Grammar::is_dictionary_type("")); 306 | EXPECT_FALSE(Grammar::is_dictionary_type("Dictionary")); 307 | EXPECT_FALSE(Grammar::is_dictionary_type("Dictionary ")); 308 | EXPECT_FALSE(Grammar::is_dictionary_type("Dictionary>")); 309 | EXPECT_FALSE(Grammar::is_dictionary_type("Dictionary, String>")); 310 | EXPECT_FALSE(Grammar::is_dictionary_type("Dictionary")); 311 | EXPECT_FALSE(Grammar::is_dictionary_type("dictionary")); 312 | EXPECT_FALSE(Grammar::is_dictionary_type("DICTIONARY")); 313 | EXPECT_FALSE(Grammar::is_dictionary_type(" Dictionary")); 314 | EXPECT_FALSE(Grammar::is_dictionary_type("Dictionary ")); 315 | } 316 | 317 | TEST(Grammar, is_container_type) { 318 | EXPECT_TRUE(Grammar::is_container_type("Vector")); 319 | EXPECT_TRUE(Grammar::is_container_type("Set")); 320 | EXPECT_TRUE(Grammar::is_container_type("Dictionary")); 321 | } 322 | 323 | TEST(Grammar, is_not_container_type) { 324 | EXPECT_FALSE(Grammar::is_container_type("Boolean")); 325 | EXPECT_FALSE(Grammar::is_container_type("Character")); 326 | EXPECT_FALSE(Grammar::is_container_type("Integer")); 327 | EXPECT_FALSE(Grammar::is_container_type("Float")); 328 | EXPECT_FALSE(Grammar::is_container_type("String")); 329 | } 330 | 331 | TEST(Grammar, is_type) { 332 | EXPECT_TRUE(Grammar::is_type("Boolean")); 333 | EXPECT_TRUE(Grammar::is_type("Character")); 334 | EXPECT_TRUE(Grammar::is_type("Integer")); 335 | EXPECT_TRUE(Grammar::is_type("Float")); 336 | EXPECT_TRUE(Grammar::is_type("String")); 337 | EXPECT_TRUE(Grammar::is_type("Vector")); 338 | EXPECT_TRUE(Grammar::is_type("Set")); 339 | EXPECT_TRUE(Grammar::is_type("Dictionary")); 340 | } 341 | 342 | TEST(Grammar, is_not_type) { 343 | EXPECT_FALSE(Grammar::is_type("")); 344 | EXPECT_FALSE(Grammar::is_type("42")); 345 | EXPECT_FALSE(Grammar::is_type("prices")); 346 | EXPECT_FALSE(Grammar::is_type("isEmpty?")); 347 | EXPECT_FALSE(Grammar::is_type(" Integer")); 348 | EXPECT_FALSE(Grammar::is_type("Vector ")); 349 | } 350 | 351 | TEST(Grammar, is_connection) { 352 | EXPECT_TRUE(Grammar::is_connection("Connection")); 353 | } 354 | 355 | TEST(Grammar, is_not_connection) { 356 | EXPECT_FALSE(Grammar::is_connection("")); 357 | EXPECT_FALSE(Grammar::is_connection("connection")); 358 | EXPECT_FALSE(Grammar::is_connection("CONNECTION")); 359 | EXPECT_FALSE(Grammar::is_connection(" Connection")); 360 | EXPECT_FALSE(Grammar::is_connection("Connection ")); 361 | } 362 | 363 | TEST(Grammar, is_context) { 364 | EXPECT_TRUE(Grammar::is_context("Context")); 365 | } 366 | 367 | TEST(Grammar, is_not_context) { 368 | EXPECT_FALSE(Grammar::is_context("")); 369 | EXPECT_FALSE(Grammar::is_context("context")); 370 | EXPECT_FALSE(Grammar::is_context("CONTEXT")); 371 | EXPECT_FALSE(Grammar::is_context(" Context")); 372 | EXPECT_FALSE(Grammar::is_context("Context ")); 373 | } 374 | 375 | TEST(Grammar, is_reserverd_word) { 376 | EXPECT_TRUE(Grammar::is_reserved_word("null")); 377 | EXPECT_TRUE(Grammar::is_reserved_word("true")); 378 | EXPECT_TRUE(Grammar::is_reserved_word("false")); 379 | EXPECT_TRUE(Grammar::is_reserved_word("Connection")); 380 | EXPECT_TRUE(Grammar::is_reserved_word("Context")); 381 | EXPECT_TRUE(Grammar::is_reserved_word("Boolean")); 382 | EXPECT_TRUE(Grammar::is_reserved_word("Character")); 383 | EXPECT_TRUE(Grammar::is_reserved_word("Integer")); 384 | EXPECT_TRUE(Grammar::is_reserved_word("Float")); 385 | EXPECT_TRUE(Grammar::is_reserved_word("String")); 386 | EXPECT_TRUE(Grammar::is_reserved_word("Vector")); 387 | EXPECT_TRUE(Grammar::is_reserved_word("Set")); 388 | EXPECT_TRUE(Grammar::is_reserved_word("Dictionary")); 389 | } 390 | 391 | TEST(Grammar, is_not_reserverd_word) { 392 | EXPECT_FALSE(Grammar::is_reserved_word("")); 393 | EXPECT_FALSE(Grammar::is_reserved_word("42")); 394 | EXPECT_FALSE(Grammar::is_reserved_word("prices")); 395 | EXPECT_FALSE(Grammar::is_reserved_word("isEmpty?")); 396 | EXPECT_FALSE(Grammar::is_reserved_word(" Integer")); 397 | EXPECT_FALSE(Grammar::is_reserved_word("Vector ")); 398 | } 399 | 400 | TEST(Grammar, is_identifier) { 401 | EXPECT_TRUE(Grammar::is_identifier("i")); 402 | EXPECT_TRUE(Grammar::is_identifier("id")); 403 | EXPECT_TRUE(Grammar::is_identifier("id2016")); 404 | EXPECT_TRUE(Grammar::is_identifier("id_2016")); 405 | } 406 | 407 | TEST(Grammar, is_not_identifier) { 408 | EXPECT_FALSE(Grammar::is_identifier("")); 409 | EXPECT_FALSE(Grammar::is_identifier("null")); 410 | EXPECT_FALSE(Grammar::is_identifier("true")); 411 | EXPECT_FALSE(Grammar::is_identifier("false")); 412 | EXPECT_FALSE(Grammar::is_identifier("Connection")); 413 | EXPECT_FALSE(Grammar::is_identifier("Context")); 414 | EXPECT_FALSE(Grammar::is_identifier("Boolean")); 415 | EXPECT_FALSE(Grammar::is_identifier("Character")); 416 | EXPECT_FALSE(Grammar::is_identifier("Integer")); 417 | EXPECT_FALSE(Grammar::is_identifier("Float")); 418 | EXPECT_FALSE(Grammar::is_identifier("String")); 419 | EXPECT_FALSE(Grammar::is_identifier("Vector")); 420 | EXPECT_FALSE(Grammar::is_identifier("Set")); 421 | EXPECT_FALSE(Grammar::is_identifier("Dictionary")); 422 | EXPECT_FALSE(Grammar::is_identifier("_id")); 423 | EXPECT_FALSE(Grammar::is_identifier("2016id")); 424 | EXPECT_FALSE(Grammar::is_identifier(" id")); 425 | EXPECT_FALSE(Grammar::is_identifier("id ")); 426 | } 427 | 428 | TEST(Grammar, is_namespace) { 429 | EXPECT_TRUE(Grammar::is_namespace("s")); 430 | EXPECT_TRUE(Grammar::is_namespace("std")); 431 | EXPECT_TRUE(Grammar::is_namespace("std2016")); 432 | EXPECT_TRUE(Grammar::is_namespace("std_2016")); 433 | } 434 | 435 | TEST(Grammar, is_not_namespace) { 436 | EXPECT_FALSE(Grammar::is_namespace("")); 437 | EXPECT_FALSE(Grammar::is_namespace("null")); 438 | EXPECT_FALSE(Grammar::is_namespace("true")); 439 | EXPECT_FALSE(Grammar::is_namespace("false")); 440 | EXPECT_FALSE(Grammar::is_namespace("Connection")); 441 | EXPECT_FALSE(Grammar::is_namespace("Context")); 442 | EXPECT_FALSE(Grammar::is_namespace("Boolean")); 443 | EXPECT_FALSE(Grammar::is_namespace("Character")); 444 | EXPECT_FALSE(Grammar::is_namespace("Integer")); 445 | EXPECT_FALSE(Grammar::is_namespace("Float")); 446 | EXPECT_FALSE(Grammar::is_namespace("String")); 447 | EXPECT_FALSE(Grammar::is_namespace("Vector")); 448 | EXPECT_FALSE(Grammar::is_namespace("Set")); 449 | EXPECT_FALSE(Grammar::is_namespace("Dictionary")); 450 | EXPECT_FALSE(Grammar::is_namespace("std:")); 451 | EXPECT_FALSE(Grammar::is_namespace("_std")); 452 | EXPECT_FALSE(Grammar::is_namespace("2016std")); 453 | EXPECT_FALSE(Grammar::is_namespace(" std")); 454 | EXPECT_FALSE(Grammar::is_namespace("std ")); 455 | } 456 | 457 | TEST(Grammar, is_variable) { 458 | EXPECT_TRUE(Grammar::is_variable("i")); 459 | EXPECT_TRUE(Grammar::is_variable("prices")); 460 | EXPECT_TRUE(Grammar::is_variable("prices2016")); 461 | EXPECT_TRUE(Grammar::is_variable("prices_2016")); 462 | EXPECT_TRUE(Grammar::is_variable("std::i")); 463 | EXPECT_TRUE(Grammar::is_variable("std::prices")); 464 | EXPECT_TRUE(Grammar::is_variable("std::prices2016")); 465 | EXPECT_TRUE(Grammar::is_variable("std::prices_2016")); 466 | } 467 | 468 | TEST(Grammar, is_not_variable) { 469 | EXPECT_FALSE(Grammar::is_variable("")); 470 | EXPECT_FALSE(Grammar::is_variable("null")); 471 | EXPECT_FALSE(Grammar::is_variable("true")); 472 | EXPECT_FALSE(Grammar::is_variable("false")); 473 | EXPECT_FALSE(Grammar::is_variable("Connection")); 474 | EXPECT_FALSE(Grammar::is_variable("Context")); 475 | EXPECT_FALSE(Grammar::is_variable("Boolean")); 476 | EXPECT_FALSE(Grammar::is_variable("Character")); 477 | EXPECT_FALSE(Grammar::is_variable("Integer")); 478 | EXPECT_FALSE(Grammar::is_variable("Float")); 479 | EXPECT_FALSE(Grammar::is_variable("String")); 480 | EXPECT_FALSE(Grammar::is_variable("Vector")); 481 | EXPECT_FALSE(Grammar::is_variable("Set")); 482 | EXPECT_FALSE(Grammar::is_variable("Dictionary")); 483 | EXPECT_FALSE(Grammar::is_variable("std::")); 484 | EXPECT_FALSE(Grammar::is_variable("::std")); 485 | EXPECT_FALSE(Grammar::is_variable("std:::")); 486 | EXPECT_FALSE(Grammar::is_variable("std:::prices")); 487 | EXPECT_FALSE(Grammar::is_variable("_prices")); 488 | EXPECT_FALSE(Grammar::is_variable("std::_prices")); 489 | EXPECT_FALSE(Grammar::is_variable("2016prices")); 490 | EXPECT_FALSE(Grammar::is_variable("std::2016prices")); 491 | EXPECT_FALSE(Grammar::is_variable("std:prices")); 492 | EXPECT_FALSE(Grammar::is_variable("std_one::std_two::prices")); 493 | EXPECT_FALSE(Grammar::is_variable(" prices")); 494 | EXPECT_FALSE(Grammar::is_variable("prices ")); 495 | } 496 | 497 | TEST(Grammar, is_actor) { 498 | EXPECT_TRUE(Grammar::is_actor("Connection")); 499 | EXPECT_TRUE(Grammar::is_actor("Context")); 500 | EXPECT_TRUE(Grammar::is_actor("Boolean")); 501 | EXPECT_TRUE(Grammar::is_actor("Character")); 502 | EXPECT_TRUE(Grammar::is_actor("Integer")); 503 | EXPECT_TRUE(Grammar::is_actor("Float")); 504 | EXPECT_TRUE(Grammar::is_actor("String")); 505 | EXPECT_TRUE(Grammar::is_actor("Vector")); 506 | EXPECT_TRUE(Grammar::is_actor("Set")); 507 | EXPECT_TRUE(Grammar::is_actor("Dictionary")); 508 | EXPECT_TRUE(Grammar::is_actor("prices")); 509 | EXPECT_TRUE(Grammar::is_actor("prices2016")); 510 | EXPECT_TRUE(Grammar::is_actor("prices_2016")); 511 | EXPECT_TRUE(Grammar::is_actor("std::prices")); 512 | EXPECT_TRUE(Grammar::is_actor("std::prices2016")); 513 | EXPECT_TRUE(Grammar::is_actor("std::prices_2016")); 514 | } 515 | 516 | TEST(Grammar, is_not_actor) { 517 | EXPECT_FALSE(Grammar::is_actor("")); 518 | EXPECT_FALSE(Grammar::is_actor("42")); 519 | EXPECT_FALSE(Grammar::is_actor("isEmpty?")); 520 | EXPECT_FALSE(Grammar::is_actor(" prices")); 521 | EXPECT_FALSE(Grammar::is_actor("prices ")); 522 | } 523 | 524 | TEST(Grammar, is_unary_message) { 525 | EXPECT_TRUE(Grammar::is_unary_message("get")); 526 | EXPECT_TRUE(Grammar::is_unary_message("isEmpty?")); 527 | } 528 | 529 | TEST(Grammar, is_not_unary_message) { 530 | EXPECT_FALSE(Grammar::is_unary_message("")); 531 | EXPECT_FALSE(Grammar::is_unary_message("42")); 532 | EXPECT_FALSE(Grammar::is_unary_message("get:")); 533 | EXPECT_FALSE(Grammar::is_unary_message(" get")); 534 | EXPECT_FALSE(Grammar::is_unary_message("get ")); 535 | } 536 | 537 | TEST(Grammar, is_keyword_message_token) { 538 | EXPECT_TRUE(Grammar::is_keyword_message_token("withValue:")); 539 | EXPECT_TRUE(Grammar::is_keyword_message_token("isEqualTo?")); 540 | } 541 | 542 | TEST(Grammar, is_not_keyword_message_token) { 543 | EXPECT_FALSE(Grammar::is_keyword_message_token("")); 544 | EXPECT_FALSE(Grammar::is_keyword_message_token("42:")); 545 | EXPECT_FALSE(Grammar::is_keyword_message_token("true?")); 546 | EXPECT_FALSE(Grammar::is_keyword_message_token("withValue")); 547 | EXPECT_FALSE(Grammar::is_keyword_message_token(" withValue:")); 548 | EXPECT_FALSE(Grammar::is_keyword_message_token("withValue: ")); 549 | } 550 | 551 | TEST(Grammar, is_keyword_message_argument) { 552 | EXPECT_TRUE(Grammar::is_keyword_message_argument("42")); 553 | EXPECT_TRUE(Grammar::is_keyword_message_argument("std")); 554 | EXPECT_TRUE(Grammar::is_keyword_message_argument("std::prices")); 555 | } 556 | 557 | TEST(Grammar, is_not_keyword_message_argument) { 558 | EXPECT_FALSE(Grammar::is_keyword_message_argument("")); 559 | EXPECT_FALSE(Grammar::is_keyword_message_argument("Connection")); 560 | EXPECT_FALSE(Grammar::is_keyword_message_argument("Context")); 561 | EXPECT_FALSE(Grammar::is_keyword_message_argument("Boolean")); 562 | EXPECT_FALSE(Grammar::is_keyword_message_argument("Vector")); 563 | EXPECT_FALSE(Grammar::is_keyword_message_argument("withValue:")); 564 | EXPECT_FALSE(Grammar::is_keyword_message_argument("isEmpty?")); 565 | EXPECT_FALSE(Grammar::is_keyword_message_argument(" 42")); 566 | EXPECT_FALSE(Grammar::is_keyword_message_argument("42 ")); 567 | } 568 | 569 | TEST(Grammar, is_keyword_message_part) { 570 | EXPECT_TRUE(Grammar::is_keyword_message_part("withValue: 42")); 571 | EXPECT_TRUE(Grammar::is_keyword_message_part("create: std::prices")); 572 | EXPECT_TRUE(Grammar::is_keyword_message_part("deleteVariablesOfNamespace: std")); 573 | } 574 | 575 | TEST(Grammar, is_keyword_message_part_corner_cases) { 576 | EXPECT_TRUE(Grammar::is_keyword_message_part("withValue:42")); 577 | EXPECT_TRUE(Grammar::is_keyword_message_part("create: std::prices")); 578 | } 579 | 580 | TEST(Grammar, is_not_keyword_message_part) { 581 | EXPECT_FALSE(Grammar::is_keyword_message_part("")); 582 | EXPECT_FALSE(Grammar::is_keyword_message_part("get")); 583 | EXPECT_FALSE(Grammar::is_keyword_message_part("withValue:")); 584 | EXPECT_FALSE(Grammar::is_keyword_message_part("withValue 42")); 585 | EXPECT_FALSE(Grammar::is_keyword_message_part("withValue: Integer")); 586 | EXPECT_FALSE(Grammar::is_keyword_message_part("create: withValue:")); 587 | EXPECT_FALSE(Grammar::is_keyword_message_part(" withValue: 42")); 588 | EXPECT_FALSE(Grammar::is_keyword_message_part("withValue: 42 ")); 589 | } 590 | 591 | TEST(Grammar, is_keyword_message) { 592 | EXPECT_TRUE(Grammar::is_keyword_message("isEqualTo? 42")); 593 | EXPECT_TRUE(Grammar::is_keyword_message("create: i withValue: 42")); 594 | } 595 | 596 | TEST(Grammar, is_keyword_message_corner_cases) { 597 | EXPECT_TRUE(Grammar::is_keyword_message("isEqualTo?42")); 598 | EXPECT_TRUE(Grammar::is_keyword_message("create: i withValue: 42")); 599 | } 600 | 601 | TEST(Grammar, is_not_keyword_message) { 602 | EXPECT_FALSE(Grammar::is_keyword_message("")); 603 | EXPECT_FALSE(Grammar::is_keyword_message("get")); 604 | EXPECT_FALSE(Grammar::is_keyword_message("isEmpty?")); 605 | EXPECT_FALSE(Grammar::is_keyword_message("withValue 42")); 606 | EXPECT_FALSE(Grammar::is_keyword_message("create: withValue:")); 607 | EXPECT_FALSE(Grammar::is_keyword_message("create: i withValue:")); 608 | EXPECT_FALSE(Grammar::is_keyword_message("create: i 42")); 609 | EXPECT_FALSE(Grammar::is_keyword_message("i withValue: 42")); 610 | EXPECT_FALSE(Grammar::is_keyword_message(" create: i withValue: 42")); 611 | EXPECT_FALSE(Grammar::is_keyword_message("create: i withValue: 42 ")); 612 | } 613 | 614 | TEST(Grammar, is_statement) { 615 | EXPECT_TRUE(Grammar::is_statement("Connection close;")); 616 | EXPECT_TRUE(Grammar::is_statement("Context listVariables;")); 617 | EXPECT_TRUE(Grammar::is_statement("Integer create: i withValue: 42;")); 618 | EXPECT_TRUE(Grammar::is_statement("Dictionary create: ages;")); 619 | EXPECT_TRUE(Grammar::is_statement("i isEqualTo? 42;")); 620 | } 621 | 622 | TEST(Grammar, is_statement_corner_cases) { 623 | EXPECT_TRUE(Grammar::is_statement("Integer create:i withValue:42;")); 624 | EXPECT_TRUE(Grammar::is_statement(" Integer create: i withValue: 42 ; ")); 625 | } 626 | 627 | TEST(Grammar, is_not_statement) { 628 | EXPECT_FALSE(Grammar::is_statement("")); 629 | EXPECT_FALSE(Grammar::is_statement(";")); 630 | EXPECT_FALSE(Grammar::is_statement("true;")); 631 | EXPECT_FALSE(Grammar::is_statement("42 get;")); 632 | EXPECT_FALSE(Grammar::is_statement("Integer create: i")); 633 | EXPECT_FALSE(Grammar::is_statement("Integer create: ;")); 634 | EXPECT_FALSE(Grammar::is_statement("create: i withValue: 42;")); 635 | } 636 | -------------------------------------------------------------------------------- /tests/instance_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "gtest/gtest.h" 27 | 28 | #include "context.h" 29 | #include "instance.h" 30 | 31 | class InstanceTest: public ::testing::Test { 32 | protected: 33 | virtual void SetUp() { 34 | Context::get_instance("", 3, 1e-9, true); 35 | } 36 | }; 37 | 38 | /////////////////////////////////////////////////////// Boolean //////////////////////////////////////////////////////// 39 | 40 | TEST_F(InstanceTest, Boolean_construction_with_representation_1) { 41 | BooleanInstance t("true"); 42 | EXPECT_EQ(t.type(), "Boolean"); 43 | EXPECT_EQ(t.name(), ""); 44 | EXPECT_EQ(t.value(), true); 45 | EXPECT_EQ(t.representation(), "true"); 46 | } 47 | 48 | TEST_F(InstanceTest, Boolean_construction_with_representation_2) { 49 | BooleanInstance f("false"); 50 | EXPECT_EQ(f.type(), "Boolean"); 51 | EXPECT_EQ(f.name(), ""); 52 | EXPECT_EQ(f.value(), false); 53 | EXPECT_EQ(f.representation(), "false"); 54 | } 55 | 56 | TEST_F(InstanceTest, Boolean_construction_with_message_1) { 57 | BooleanInstance t("create:withValue:", std::vector({"b", "true"})); 58 | EXPECT_EQ(t.type(), "Boolean"); 59 | EXPECT_EQ(t.name(), "b"); 60 | EXPECT_EQ(t.value(), true); 61 | EXPECT_EQ(t.representation(), "true"); 62 | } 63 | 64 | TEST_F(InstanceTest, Boolean_construction_with_message_2) { 65 | BooleanInstance f("create:withValue:", std::vector({"b", "false"})); 66 | EXPECT_EQ(f.type(), "Boolean"); 67 | EXPECT_EQ(f.name(), "b"); 68 | EXPECT_EQ(f.value(), false); 69 | EXPECT_EQ(f.representation(), "false"); 70 | } 71 | 72 | TEST_F(InstanceTest, Boolean_construction_with_message_3) { 73 | BooleanInstance t("createIfNotExists:withValue:", std::vector({"b", "true"})); 74 | EXPECT_EQ(t.type(), "Boolean"); 75 | EXPECT_EQ(t.name(), "b"); 76 | EXPECT_EQ(t.value(), true); 77 | EXPECT_EQ(t.representation(), "true"); 78 | } 79 | 80 | TEST_F(InstanceTest, Boolean_construction_with_message_4) { 81 | BooleanInstance f("createIfNotExists:withValue:", std::vector({"b", "false"})); 82 | EXPECT_EQ(f.type(), "Boolean"); 83 | EXPECT_EQ(f.name(), "b"); 84 | EXPECT_EQ(f.value(), false); 85 | EXPECT_EQ(f.representation(), "false"); 86 | } 87 | 88 | TEST_F(InstanceTest, Boolean_invalid_constructions) { 89 | EXPECT_ANY_THROW(BooleanInstance("42")); 90 | EXPECT_ANY_THROW(BooleanInstance("create:withValue:", std::vector({"t"}))); 91 | EXPECT_ANY_THROW(BooleanInstance("create:withValue:", std::vector({"t", "42"}))); 92 | EXPECT_ANY_THROW(BooleanInstance("create:withValue:", std::vector({"true", "t"}))); 93 | EXPECT_ANY_THROW(BooleanInstance("createIfNotExists:withValue:", std::vector({"t"}))); 94 | EXPECT_ANY_THROW(BooleanInstance("createIfNotExists:withValue:", std::vector({"t", "42"}))); 95 | EXPECT_ANY_THROW(BooleanInstance("createIfNotExists:withValue:", std::vector({"true", "t"}))); 96 | } 97 | 98 | ////////////////////////////////////////////////////// Character /////////////////////////////////////////////////////// 99 | 100 | TEST_F(InstanceTest, Character_construction_with_representation) { 101 | CharacterInstance numeric("'1'"); 102 | EXPECT_EQ(numeric.type(), "Character"); 103 | EXPECT_EQ(numeric.name(), ""); 104 | EXPECT_EQ(numeric.value(), '1'); 105 | EXPECT_EQ(numeric.representation(), "'1'"); 106 | } 107 | 108 | TEST_F(InstanceTest, Character_construction_with_message_1) { 109 | CharacterInstance numeric("create:withValue:", std::vector({"numeric", "'1'"})); 110 | EXPECT_EQ(numeric.type(), "Character"); 111 | EXPECT_EQ(numeric.name(), "numeric"); 112 | EXPECT_EQ(numeric.value(), '1'); 113 | EXPECT_EQ(numeric.representation(), "'1'"); 114 | } 115 | 116 | TEST_F(InstanceTest, Character_construction_with_message_2) { 117 | CharacterInstance numeric("createIfNotExists:withValue:", std::vector({"numeric", "'1'"})); 118 | EXPECT_EQ(numeric.type(), "Character"); 119 | EXPECT_EQ(numeric.name(), "numeric"); 120 | EXPECT_EQ(numeric.value(), '1'); 121 | EXPECT_EQ(numeric.representation(), "'1'"); 122 | } 123 | 124 | TEST_F(InstanceTest, CharacterInstance_invalid_constructions) { 125 | EXPECT_ANY_THROW(CharacterInstance("42")); 126 | EXPECT_ANY_THROW(CharacterInstance("create:withValue:", std::vector({"numeric"}))); 127 | EXPECT_ANY_THROW(CharacterInstance("create:withValue:", std::vector({"numeric", "42"}))); 128 | EXPECT_ANY_THROW(CharacterInstance("create:withValue:", std::vector({"'1'", "numeric"}))); 129 | EXPECT_ANY_THROW(CharacterInstance("createIfNotExists:withValue:", std::vector({"numeric"}))); 130 | EXPECT_ANY_THROW(CharacterInstance("createIfNotExists:withValue:", std::vector({"numeric", "42"}))); 131 | EXPECT_ANY_THROW(CharacterInstance("createIfNotExists:withValue:", std::vector({"'1'", "numeric"}))); 132 | } 133 | 134 | /////////////////////////////////////////////////////// Integer //////////////////////////////////////////////////////// 135 | 136 | TEST_F(InstanceTest, Integer_construction_with_value) { 137 | IntegerInstance i(42); 138 | EXPECT_EQ(i.type(), "Integer"); 139 | EXPECT_EQ(i.name(), ""); 140 | EXPECT_EQ(i.value(), 42); 141 | EXPECT_EQ(i.representation(), "42"); 142 | } 143 | 144 | TEST_F(InstanceTest, Integer_construction_with_representation_1) { 145 | IntegerInstance i("+42"); 146 | EXPECT_EQ(i.type(), "Integer"); 147 | EXPECT_EQ(i.name(), ""); 148 | EXPECT_EQ(i.value(), 42); 149 | EXPECT_EQ(i.representation(), "42"); 150 | } 151 | 152 | TEST_F(InstanceTest, Integer_construction_with_representation_2) { 153 | IntegerInstance i("-42"); 154 | EXPECT_EQ(i.type(), "Integer"); 155 | EXPECT_EQ(i.name(), ""); 156 | EXPECT_EQ(i.value(), -42); 157 | EXPECT_EQ(i.representation(), "-42"); 158 | } 159 | 160 | TEST_F(InstanceTest, Integer_construction_with_representation_3) { 161 | IntegerInstance i("42.9"); 162 | EXPECT_EQ(i.type(), "Integer"); 163 | EXPECT_EQ(i.name(), ""); 164 | EXPECT_EQ(i.value(), 42); 165 | EXPECT_EQ(i.representation(), "42"); 166 | } 167 | 168 | TEST_F(InstanceTest, Integer_construction_with_message_1) { 169 | IntegerInstance i("create:withValue:", std::vector({"i", "42"})); 170 | EXPECT_EQ(i.type(), "Integer"); 171 | EXPECT_EQ(i.name(), "i"); 172 | EXPECT_EQ(i.value(), 42); 173 | EXPECT_EQ(i.representation(), "42"); 174 | } 175 | 176 | TEST_F(InstanceTest, Integer_construction_with_message_2) { 177 | IntegerInstance i("create:withValue:", std::vector({"i", "-42"})); 178 | EXPECT_EQ(i.type(), "Integer"); 179 | EXPECT_EQ(i.name(), "i"); 180 | EXPECT_EQ(i.value(), -42); 181 | EXPECT_EQ(i.representation(), "-42"); 182 | } 183 | 184 | TEST_F(InstanceTest, Integer_construction_with_message_3) { 185 | IntegerInstance i("create:withValue:", std::vector({"i", "42.9"})); 186 | EXPECT_EQ(i.type(), "Integer"); 187 | EXPECT_EQ(i.name(), "i"); 188 | EXPECT_EQ(i.value(), 42); 189 | EXPECT_EQ(i.representation(), "42"); 190 | } 191 | 192 | TEST_F(InstanceTest, Integer_construction_with_message_4) { 193 | IntegerInstance i("createIfNotExists:withValue:", std::vector({"i", "42"})); 194 | EXPECT_EQ(i.type(), "Integer"); 195 | EXPECT_EQ(i.name(), "i"); 196 | EXPECT_EQ(i.value(), 42); 197 | EXPECT_EQ(i.representation(), "42"); 198 | } 199 | 200 | TEST_F(InstanceTest, Integer_construction_with_message_5) { 201 | IntegerInstance i("createIfNotExists:withValue:", std::vector({"i", "-42"})); 202 | EXPECT_EQ(i.type(), "Integer"); 203 | EXPECT_EQ(i.name(), "i"); 204 | EXPECT_EQ(i.value(), -42); 205 | EXPECT_EQ(i.representation(), "-42"); 206 | } 207 | 208 | TEST_F(InstanceTest, Integer_construction_with_message_6) { 209 | IntegerInstance i("createIfNotExists:withValue:", std::vector({"i", "42.9"})); 210 | EXPECT_EQ(i.type(), "Integer"); 211 | EXPECT_EQ(i.name(), "i"); 212 | EXPECT_EQ(i.value(), 42); 213 | EXPECT_EQ(i.representation(), "42"); 214 | } 215 | 216 | TEST_F(InstanceTest, Integer_invalid_constructions) { 217 | EXPECT_ANY_THROW(IntegerInstance("true")); 218 | EXPECT_ANY_THROW(IntegerInstance("create:withValue:", std::vector({"i"}))); 219 | EXPECT_ANY_THROW(IntegerInstance("create:withValue:", std::vector({"i", "true"}))); 220 | EXPECT_ANY_THROW(IntegerInstance("create:withValue:", std::vector({"42", "i"}))); 221 | EXPECT_ANY_THROW(IntegerInstance("createIfNotExists:withValue:", std::vector({"i"}))); 222 | EXPECT_ANY_THROW(IntegerInstance("createIfNotExists:withValue:", std::vector({"i", "true"}))); 223 | EXPECT_ANY_THROW(IntegerInstance("createIfNotExists:withValue:", std::vector({"42", "i"}))); 224 | } 225 | 226 | //////////////////////////////////////////////////////// Float ///////////////////////////////////////////////////////// 227 | 228 | TEST_F(InstanceTest, Float_construction_with_value) { 229 | FloatInstance f(42.0); 230 | EXPECT_EQ(f.type(), "Float"); 231 | EXPECT_EQ(f.name(), ""); 232 | EXPECT_EQ(f.representation(), "42.000"); 233 | } 234 | 235 | TEST_F(InstanceTest, Float_construction_with_representation_1) { 236 | FloatInstance f("42"); 237 | EXPECT_EQ(f.type(), "Float"); 238 | EXPECT_EQ(f.name(), ""); 239 | EXPECT_EQ(f.representation(), "42.000"); 240 | } 241 | 242 | TEST_F(InstanceTest, Float_construction_with_representation_2) { 243 | FloatInstance f("-42.0"); 244 | EXPECT_EQ(f.type(), "Float"); 245 | EXPECT_EQ(f.name(), ""); 246 | EXPECT_EQ(f.representation(), "-42.000"); 247 | } 248 | 249 | TEST_F(InstanceTest, Float_construction_with_representation_3) { 250 | FloatInstance f("1e-3"); 251 | EXPECT_EQ(f.type(), "Float"); 252 | EXPECT_EQ(f.name(), ""); 253 | EXPECT_EQ(f.representation(), "0.001"); 254 | } 255 | 256 | TEST_F(InstanceTest, Float_construction_with_message_1) { 257 | FloatInstance f("create:withValue:", std::vector({"f", "42"})); 258 | EXPECT_EQ(f.type(), "Float"); 259 | EXPECT_EQ(f.name(), "f"); 260 | EXPECT_EQ(f.representation(), "42.000"); 261 | } 262 | 263 | TEST_F(InstanceTest, Float_construction_with_message_2) { 264 | FloatInstance f("create:withValue:", std::vector({"f", "-42.0"})); 265 | EXPECT_EQ(f.type(), "Float"); 266 | EXPECT_EQ(f.name(), "f"); 267 | EXPECT_EQ(f.representation(), "-42.000"); 268 | } 269 | 270 | TEST_F(InstanceTest, Float_construction_with_message_3) { 271 | FloatInstance f("create:withValue:", std::vector({"f", "1e-3"})); 272 | EXPECT_EQ(f.type(), "Float"); 273 | EXPECT_EQ(f.name(), "f"); 274 | EXPECT_EQ(f.representation(), "0.001"); 275 | } 276 | 277 | TEST_F(InstanceTest, Float_construction_with_message_4) { 278 | FloatInstance f("createIfNotExists:withValue:", std::vector({"f", "42"})); 279 | EXPECT_EQ(f.type(), "Float"); 280 | EXPECT_EQ(f.name(), "f"); 281 | EXPECT_EQ(f.representation(), "42.000"); 282 | } 283 | 284 | TEST_F(InstanceTest, Float_construction_with_message_5) { 285 | FloatInstance f("createIfNotExists:withValue:", std::vector({"f", "-42.0"})); 286 | EXPECT_EQ(f.type(), "Float"); 287 | EXPECT_EQ(f.name(), "f"); 288 | EXPECT_EQ(f.representation(), "-42.000"); 289 | } 290 | 291 | TEST_F(InstanceTest, Float_construction_with_message_6) { 292 | FloatInstance f("createIfNotExists:withValue:", std::vector({"f", "1e-3"})); 293 | EXPECT_EQ(f.type(), "Float"); 294 | EXPECT_EQ(f.name(), "f"); 295 | EXPECT_EQ(f.representation(), "0.001"); 296 | } 297 | 298 | TEST_F(InstanceTest, Float_invalid_constructions) { 299 | EXPECT_ANY_THROW(FloatInstance("true")); 300 | EXPECT_ANY_THROW(FloatInstance("create:withValue:", std::vector({"f"}))); 301 | EXPECT_ANY_THROW(FloatInstance("create:withValue:", std::vector({"f", "true"}))); 302 | EXPECT_ANY_THROW(FloatInstance("create:withValue:", std::vector({"42.0", "f"}))); 303 | EXPECT_ANY_THROW(FloatInstance("createIfNotExists:withValue:", std::vector({"f"}))); 304 | EXPECT_ANY_THROW(FloatInstance("createIfNotExists:withValue:", std::vector({"f", "true"}))); 305 | EXPECT_ANY_THROW(FloatInstance("createIfNotExists:withValue:", std::vector({"42.0", "f"}))); 306 | } 307 | 308 | //////////////////////////////////////////////////////// String //////////////////////////////////////////////////////// 309 | 310 | TEST_F(InstanceTest, String_construction_with_representation_1) { 311 | StringInstance str("\"\""); 312 | EXPECT_EQ(str.type(), "String"); 313 | EXPECT_EQ(str.name(), ""); 314 | EXPECT_EQ(str.value(), ""); 315 | EXPECT_EQ(str.representation(), "\"\""); 316 | } 317 | 318 | TEST_F(InstanceTest, String_construction_with_representation_2) { 319 | StringInstance str("\"knuckleball\""); 320 | EXPECT_EQ(str.type(), "String"); 321 | EXPECT_EQ(str.name(), ""); 322 | EXPECT_EQ(str.value(), "knuckleball"); 323 | EXPECT_EQ(str.representation(), "\"knuckleball\""); 324 | } 325 | 326 | TEST_F(InstanceTest, String_construction_with_message_1) { 327 | StringInstance str("create:", std::vector({"str"})); 328 | EXPECT_EQ(str.type(), "String"); 329 | EXPECT_EQ(str.name(), "str"); 330 | EXPECT_EQ(str.value(), ""); 331 | EXPECT_EQ(str.representation(), "\"\""); 332 | } 333 | 334 | TEST_F(InstanceTest, String_construction_with_message_2) { 335 | StringInstance str("createIfNotExists:", std::vector({"str"})); 336 | EXPECT_EQ(str.type(), "String"); 337 | EXPECT_EQ(str.name(), "str"); 338 | EXPECT_EQ(str.value(), ""); 339 | EXPECT_EQ(str.representation(), "\"\""); 340 | } 341 | 342 | TEST_F(InstanceTest, String_construction_with_message_3) { 343 | StringInstance str("create:withValue:", std::vector({"str", "\"knuckleball\""})); 344 | EXPECT_EQ(str.type(), "String"); 345 | EXPECT_EQ(str.name(), "str"); 346 | EXPECT_EQ(str.value(), "knuckleball"); 347 | EXPECT_EQ(str.representation(), "\"knuckleball\""); 348 | } 349 | 350 | TEST_F(InstanceTest, String_construction_with_message_4) { 351 | StringInstance str("create:withValue:", std::vector({"str", "\"knuckle\\\"ball\""})); 352 | EXPECT_EQ(str.type(), "String"); 353 | EXPECT_EQ(str.name(), "str"); 354 | EXPECT_EQ(str.value(), "knuckle\"ball"); 355 | EXPECT_EQ(str.representation(), "\"knuckle\\\"ball\""); 356 | } 357 | 358 | TEST_F(InstanceTest, String_construction_with_message_5) { 359 | StringInstance str("createIfNotExists:withValue:", std::vector({"str", "\"knuckleball\""})); 360 | EXPECT_EQ(str.type(), "String"); 361 | EXPECT_EQ(str.name(), "str"); 362 | EXPECT_EQ(str.value(), "knuckleball"); 363 | EXPECT_EQ(str.representation(), "\"knuckleball\""); 364 | } 365 | 366 | TEST_F(InstanceTest, String_construction_with_message_6) { 367 | StringInstance str("createIfNotExists:withValue:", std::vector({"str", "\"knuckle\\\"ball\""})); 368 | EXPECT_EQ(str.type(), "String"); 369 | EXPECT_EQ(str.name(), "str"); 370 | EXPECT_EQ(str.value(), "knuckle\"ball"); 371 | EXPECT_EQ(str.representation(), "\"knuckle\\\"ball\""); 372 | } 373 | 374 | TEST_F(InstanceTest, String_invalid_constructions) { 375 | EXPECT_ANY_THROW(StringInstance("42")); 376 | EXPECT_ANY_THROW(StringInstance("create:", std::vector())); 377 | EXPECT_ANY_THROW(StringInstance("createIfNotExists:", std::vector())); 378 | EXPECT_ANY_THROW(StringInstance("create:withValue:", std::vector({"str"}))); 379 | EXPECT_ANY_THROW(StringInstance("create:withValue:", std::vector({"str", "42"}))); 380 | EXPECT_ANY_THROW(StringInstance("create:withValue:", std::vector({"\"knuckleball\"", "str"}))); 381 | EXPECT_ANY_THROW(StringInstance("createIfNotExists:withValue:", std::vector({"str"}))); 382 | EXPECT_ANY_THROW(StringInstance("createIfNotExists:withValue:", std::vector({"str", "42"}))); 383 | EXPECT_ANY_THROW(StringInstance("createIfNotExists:withValue:", std::vector({"\"knuckleball\"", "str"}))); 384 | } 385 | 386 | //////////////////////////////////////////////////////// Vector //////////////////////////////////////////////////////// 387 | 388 | TEST_F(InstanceTest, Vector_construction) { 389 | VectorInstance prices("Integer", "create:", std::vector({"prices"})); 390 | EXPECT_EQ(prices.type(), "Vector"); 391 | EXPECT_EQ(prices.name(), "prices"); 392 | EXPECT_EQ(prices.representation(), "[]"); 393 | } 394 | 395 | TEST_F(InstanceTest, Vector_invalid_constructions) { 396 | EXPECT_ANY_THROW(VectorInstance("Integer", "create:", std::vector())); 397 | EXPECT_ANY_THROW(VectorInstance("Integer", "create:", std::vector({"42"}))); 398 | EXPECT_ANY_THROW(VectorInstance("Integer", "create:", std::vector({"prices", "42"}))); 399 | } 400 | 401 | ///////////////////////////////////////////////////////// Set ////////////////////////////////////////////////////////// 402 | 403 | TEST_F(InstanceTest, Set_construction) { 404 | SetInstance ids("String", "create:", std::vector({"ids"})); 405 | EXPECT_EQ(ids.type(), "Set"); 406 | EXPECT_EQ(ids.name(), "ids"); 407 | EXPECT_EQ(ids.representation(), "{}"); 408 | } 409 | 410 | TEST_F(InstanceTest, Set_invalid_constructions) { 411 | EXPECT_ANY_THROW(SetInstance("String", "create:", std::vector())); 412 | EXPECT_ANY_THROW(SetInstance("String", "create:", std::vector({"42"}))); 413 | EXPECT_ANY_THROW(SetInstance("String", "create:", std::vector({"ids", "42"}))); 414 | } 415 | 416 | ////////////////////////////////////////////////////// Dictionary ////////////////////////////////////////////////////// 417 | 418 | TEST_F(InstanceTest, Dictionary_construction) { 419 | DictionaryInstance ages("String", "Integer", "create:", std::vector({"ages"})); 420 | EXPECT_EQ(ages.type(), "Dictionary"); 421 | EXPECT_EQ(ages.name(), "ages"); 422 | EXPECT_EQ(ages.representation(), "()"); 423 | } 424 | 425 | TEST_F(InstanceTest, Dictionary_invalid_constructions) { 426 | EXPECT_ANY_THROW(DictionaryInstance("String", "Integer", "create:", std::vector())); 427 | EXPECT_ANY_THROW(DictionaryInstance("String", "Integer", "create:", std::vector({"42"}))); 428 | EXPECT_ANY_THROW(DictionaryInstance("String", "Integer", "create:", std::vector({"ages", "42"}))); 429 | } 430 | -------------------------------------------------------------------------------- /tests/parser_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "gtest/gtest.h" 27 | 28 | #include "parser.h" 29 | 30 | /////////////////////////////////////////////////// Valid statements /////////////////////////////////////////////////// 31 | 32 | TEST(Parser, valid_statement_1) { 33 | Parser parser("Boolean create: b withValue: true;"); 34 | EXPECT_EQ(parser.actor(), "Boolean"); 35 | EXPECT_EQ(parser.message_name(), "create:withValue:"); 36 | EXPECT_EQ(parser.arguments(), std::vector({"b", "true"})); 37 | } 38 | 39 | TEST(Parser, valid_statement_2) { 40 | Parser parser("b get;"); 41 | EXPECT_EQ(parser.actor(), "b"); 42 | EXPECT_EQ(parser.message_name(), "get"); 43 | EXPECT_EQ(parser.arguments(), std::vector({})); 44 | } 45 | 46 | TEST(Parser, valid_statement_3) { 47 | Parser parser("b isTrue?;"); 48 | EXPECT_EQ(parser.actor(), "b"); 49 | EXPECT_EQ(parser.message_name(), "isTrue?"); 50 | EXPECT_EQ(parser.arguments(), std::vector({})); 51 | } 52 | 53 | TEST(Parser, valid_statement_4) { 54 | Parser parser("b set: false;"); 55 | EXPECT_EQ(parser.actor(), "b"); 56 | EXPECT_EQ(parser.message_name(), "set:"); 57 | EXPECT_EQ(parser.arguments(), std::vector({"false"})); 58 | } 59 | 60 | TEST(Parser, valid_statement_5) { 61 | Parser parser("Character create: numeric withValue: '1';"); 62 | EXPECT_EQ(parser.actor(), "Character"); 63 | EXPECT_EQ(parser.message_name(), "create:withValue:"); 64 | EXPECT_EQ(parser.arguments(), std::vector({"numeric", "'1'"})); 65 | } 66 | 67 | TEST(Parser, valid_statement_6) { 68 | Parser parser("i isEqualTo? -42;"); 69 | EXPECT_EQ(parser.actor(), "i"); 70 | EXPECT_EQ(parser.message_name(), "isEqualTo?"); 71 | EXPECT_EQ(parser.arguments(), std::vector({"-42"})); 72 | } 73 | 74 | TEST(Parser, valid_statement_7) { 75 | Parser parser("Float createIfNotExists: f withValue: -42.0;"); 76 | EXPECT_EQ(parser.actor(), "Float"); 77 | EXPECT_EQ(parser.message_name(), "createIfNotExists:withValue:"); 78 | EXPECT_EQ(parser.arguments(), std::vector({"f", "-42.0"})); 79 | } 80 | 81 | TEST(Parser, valid_statement_8) { 82 | Parser parser("String create: str withValue: \"knuckleball\";"); 83 | EXPECT_EQ(parser.actor(), "String"); 84 | EXPECT_EQ(parser.message_name(), "create:withValue:"); 85 | EXPECT_EQ(parser.arguments(), std::vector({"str", "\"knuckleball\""})); 86 | } 87 | 88 | TEST(Parser, valid_statement_9) { 89 | Parser parser("str replaceFirst: \"knuckle\" fromIndex: 0 with: \"ball\";"); 90 | EXPECT_EQ(parser.actor(), "str"); 91 | EXPECT_EQ(parser.message_name(), "replaceFirst:fromIndex:with:"); 92 | EXPECT_EQ(parser.arguments(), std::vector({"\"knuckle\"", "0", "\"ball\""})); 93 | } 94 | 95 | TEST(Parser, valid_statement_10) { 96 | Parser parser("Vector create: prices;"); 97 | EXPECT_EQ(parser.actor(), "Vector"); 98 | EXPECT_EQ(parser.message_name(), "create:"); 99 | EXPECT_EQ(parser.arguments(), std::vector({"prices"})); 100 | } 101 | 102 | TEST(Parser, valid_statement_11) { 103 | Parser parser("Set create: ids;"); 104 | EXPECT_EQ(parser.actor(), "Set"); 105 | EXPECT_EQ(parser.message_name(), "create:"); 106 | EXPECT_EQ(parser.arguments(), std::vector({"ids"})); 107 | } 108 | 109 | TEST(Parser, valid_statement_12) { 110 | Parser parser("Dictionary create: ages;"); 111 | EXPECT_EQ(parser.actor(), "Dictionary"); 112 | EXPECT_EQ(parser.message_name(), "create:"); 113 | EXPECT_EQ(parser.arguments(), std::vector({"ages"})); 114 | } 115 | 116 | TEST(Parser, valid_statement_13) { 117 | Parser parser("Context listVariablesOfNamespace: std;"); 118 | EXPECT_EQ(parser.actor(), "Context"); 119 | EXPECT_EQ(parser.message_name(), "listVariablesOfNamespace:"); 120 | EXPECT_EQ(parser.arguments(), std::vector({"std"})); 121 | } 122 | 123 | ///////////////////////////////////////////////////// Corner cases ///////////////////////////////////////////////////// 124 | 125 | TEST(Parser, corner_case_1) { 126 | Parser parser(" prices get ; "); 127 | EXPECT_EQ(parser.actor(), "prices"); 128 | EXPECT_EQ(parser.message_name(), "get"); 129 | EXPECT_EQ(parser.arguments(), std::vector({})); 130 | } 131 | 132 | TEST(Parser, corner_case_2) { 133 | Parser parser(" Integer create: i withValue: +42 ;"); 134 | EXPECT_EQ(parser.actor(), "Integer"); 135 | EXPECT_EQ(parser.message_name(), "create:withValue:"); 136 | EXPECT_EQ(parser.arguments(), std::vector({"i", "+42"})); 137 | } 138 | 139 | TEST(Parser, corner_case_3) { 140 | Parser parser("Integer create:i withValue:-42;"); 141 | EXPECT_EQ(parser.actor(), "Integer"); 142 | EXPECT_EQ(parser.message_name(), "create:withValue:"); 143 | EXPECT_EQ(parser.arguments(), std::vector({"i", "-42"})); 144 | } 145 | 146 | TEST(Parser, corner_case_4) { 147 | Parser parser("String create: str withValue: \"one two three four\";"); 148 | EXPECT_EQ(parser.actor(), "String"); 149 | EXPECT_EQ(parser.message_name(), "create:withValue:"); 150 | EXPECT_EQ(parser.arguments(), std::vector({"str", "\"one two three four\""})); 151 | } 152 | 153 | ////////////////////////////////////////////////// Invalid statements ////////////////////////////////////////////////// 154 | 155 | TEST(Parser, invalid_statements) { 156 | // invalid syntax: 157 | EXPECT_ANY_THROW(Parser("42;")); 158 | EXPECT_ANY_THROW(Parser("true;")); 159 | 160 | // invalid actor: 161 | EXPECT_ANY_THROW(Parser("42 add: 1;")); 162 | EXPECT_ANY_THROW(Parser("true get;")); 163 | 164 | // missing message: 165 | EXPECT_ANY_THROW(Parser("Integer;")); 166 | EXPECT_ANY_THROW(Parser("Context;")); 167 | EXPECT_ANY_THROW(Parser("std::prices;")); 168 | 169 | // missing actor: 170 | EXPECT_ANY_THROW(Parser("create: i withValue: 42;")); 171 | 172 | // missing semicolon: 173 | EXPECT_ANY_THROW(Parser("Integer create: i withValue: 42")); 174 | 175 | // missing argument: 176 | EXPECT_ANY_THROW(Parser("Integer create: i withValue: ;")); 177 | EXPECT_ANY_THROW(Parser("Integer create: withValue: 42;")); 178 | } 179 | -------------------------------------------------------------------------------- /tests/str_utils_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016, Rodrigo Alves Lima 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 6 | following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 9 | following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 12 | following disclaimer in the documentation and/or other materials provided with the distribution. 13 | 14 | 3. Neither the name of Knuckleball nor the names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | #include "gtest/gtest.h" 27 | 28 | #include "str_utils.h" 29 | 30 | TEST(str_utils, ltrim) { 31 | EXPECT_EQ(str_utils::ltrim(""), ""); 32 | EXPECT_EQ(str_utils::ltrim(" "), ""); 33 | EXPECT_EQ(str_utils::ltrim(" "), ""); 34 | EXPECT_EQ(str_utils::ltrim("Integer"), "Integer"); 35 | EXPECT_EQ(str_utils::ltrim(" Integer"), "Integer"); 36 | EXPECT_EQ(str_utils::ltrim("Integer "), "Integer "); 37 | EXPECT_EQ(str_utils::ltrim(" Integer "), "Integer "); 38 | } 39 | 40 | TEST(str_utils, rtrim) { 41 | EXPECT_EQ(str_utils::rtrim(""), ""); 42 | EXPECT_EQ(str_utils::rtrim(" "), ""); 43 | EXPECT_EQ(str_utils::rtrim(" "), ""); 44 | EXPECT_EQ(str_utils::rtrim("Integer"), "Integer"); 45 | EXPECT_EQ(str_utils::rtrim(" Integer"), " Integer"); 46 | EXPECT_EQ(str_utils::rtrim("Integer "), "Integer"); 47 | EXPECT_EQ(str_utils::rtrim(" Integer "), " Integer"); 48 | } 49 | 50 | TEST(str_utils, trim) { 51 | EXPECT_EQ(str_utils::trim(""), ""); 52 | EXPECT_EQ(str_utils::trim(" "), ""); 53 | EXPECT_EQ(str_utils::trim(" "), ""); 54 | EXPECT_EQ(str_utils::trim("Integer"), "Integer"); 55 | EXPECT_EQ(str_utils::trim(" Integer"), "Integer"); 56 | EXPECT_EQ(str_utils::trim("Integer "), "Integer"); 57 | EXPECT_EQ(str_utils::trim(" Integer "), "Integer"); 58 | } 59 | 60 | TEST(str_utils, escape) { 61 | EXPECT_EQ(str_utils::escape("", 'a'), ""); 62 | EXPECT_EQ(str_utils::escape("knuckleball", 'l'), "knuck\\leba\\l\\l"); 63 | EXPECT_EQ(str_utils::escape("\\knuckleball", 'l'), "\\knuck\\leba\\l\\l"); 64 | } 65 | 66 | TEST(str_utils, unescape) { 67 | EXPECT_EQ(str_utils::unescape("", 'a'), ""); 68 | EXPECT_EQ(str_utils::unescape("\\knuck\\leba\\l\\l", 'l'), "\\knuckleball"); 69 | EXPECT_EQ(str_utils::unescape("\\knuck\\leba\\l\\l", 'k'), "knuck\\leba\\l\\l"); 70 | } 71 | 72 | TEST(str_utils, is_space) { 73 | EXPECT_TRUE(str_utils::is_space(' ')); 74 | EXPECT_TRUE(str_utils::is_space('\n')); 75 | EXPECT_TRUE(str_utils::is_space('\t')); 76 | } 77 | 78 | TEST(str_utils, is_not_space) { 79 | EXPECT_FALSE(str_utils::is_space('0')); 80 | EXPECT_FALSE(str_utils::is_space('9')); 81 | EXPECT_FALSE(str_utils::is_space('a')); 82 | EXPECT_FALSE(str_utils::is_space('z')); 83 | EXPECT_FALSE(str_utils::is_space('A')); 84 | EXPECT_FALSE(str_utils::is_space('Z')); 85 | EXPECT_FALSE(str_utils::is_space(',')); 86 | } 87 | 88 | TEST(str_utils, is_alpha) { 89 | EXPECT_TRUE(str_utils::is_alpha('a')); 90 | EXPECT_TRUE(str_utils::is_alpha('z')); 91 | EXPECT_TRUE(str_utils::is_alpha('A')); 92 | EXPECT_TRUE(str_utils::is_alpha('Z')); 93 | } 94 | 95 | TEST(str_utils, is_not_alpha) { 96 | EXPECT_FALSE(str_utils::is_alpha(' ')); 97 | EXPECT_FALSE(str_utils::is_alpha('0')); 98 | EXPECT_FALSE(str_utils::is_alpha('9')); 99 | EXPECT_FALSE(str_utils::is_alpha(',')); 100 | } 101 | 102 | TEST(str_utils, is_numeric) { 103 | EXPECT_TRUE(str_utils::is_numeric('0')); 104 | EXPECT_TRUE(str_utils::is_numeric('9')); 105 | } 106 | 107 | TEST(str_utils, is_not_numeric) { 108 | EXPECT_FALSE(str_utils::is_numeric(' ')); 109 | EXPECT_FALSE(str_utils::is_numeric('a')); 110 | EXPECT_FALSE(str_utils::is_numeric('z')); 111 | EXPECT_FALSE(str_utils::is_numeric('A')); 112 | EXPECT_FALSE(str_utils::is_numeric('Z')); 113 | EXPECT_FALSE(str_utils::is_numeric(',')); 114 | } 115 | 116 | TEST(str_utils, is_alphanumeric) { 117 | EXPECT_TRUE(str_utils::is_alphanumeric('a')); 118 | EXPECT_TRUE(str_utils::is_alphanumeric('z')); 119 | EXPECT_TRUE(str_utils::is_alphanumeric('A')); 120 | EXPECT_TRUE(str_utils::is_alphanumeric('Z')); 121 | EXPECT_TRUE(str_utils::is_alphanumeric('0')); 122 | EXPECT_TRUE(str_utils::is_alphanumeric('9')); 123 | } 124 | 125 | TEST(str_utils, is_not_alphanumeric) { 126 | EXPECT_FALSE(str_utils::is_alphanumeric(' ')); 127 | EXPECT_FALSE(str_utils::is_alphanumeric(',')); 128 | } 129 | 130 | TEST(str_utils, starts_with) { 131 | EXPECT_TRUE(str_utils::starts_with("", "")); 132 | EXPECT_TRUE(str_utils::starts_with("knuckleball", "")); 133 | EXPECT_TRUE(str_utils::starts_with("knuckleball", "knuckleball")); 134 | EXPECT_TRUE(str_utils::starts_with("knuckleball", "knuckle")); 135 | } 136 | 137 | TEST(str_utils, do_not_starts_with) { 138 | EXPECT_FALSE(str_utils::starts_with("", "knuckleball")); 139 | EXPECT_FALSE(str_utils::starts_with("knuckleball", "ball")); 140 | } 141 | 142 | TEST(str_utils, ends_with) { 143 | EXPECT_TRUE(str_utils::ends_with("", "")); 144 | EXPECT_TRUE(str_utils::ends_with("knuckleball", "")); 145 | EXPECT_TRUE(str_utils::ends_with("knuckleball", "knuckleball")); 146 | EXPECT_TRUE(str_utils::ends_with("knuckleball", "ball")); 147 | } 148 | 149 | TEST(str_utils, do_not_ends_with) { 150 | EXPECT_FALSE(str_utils::ends_with("", "knuckleball")); 151 | EXPECT_FALSE(str_utils::ends_with("knuckleball", "knuckle")); 152 | } 153 | 154 | TEST(str_utils, remove_spaces) { 155 | EXPECT_EQ(str_utils::remove_spaces(""), ""); 156 | EXPECT_EQ(str_utils::remove_spaces(" "), ""); 157 | EXPECT_EQ(str_utils::remove_spaces("knuckleball"), "knuckleball"); 158 | EXPECT_EQ(str_utils::remove_spaces(" knuckle\nball\t"), "knuckleball"); 159 | } 160 | --------------------------------------------------------------------------------