├── .gitignore ├── README.md ├── signal.sln └── signal ├── AST.cpp ├── AST.h ├── Code.h ├── Compiler.cpp ├── Compiler.h ├── Enviroment.cpp ├── Enviroment.h ├── Error.cpp ├── Error.h ├── FileInput.cpp ├── FileInput.h ├── Interpreter.cpp ├── Interpreter.h ├── Lexer.cpp ├── Lexer.h ├── Object.cpp ├── Object.h ├── Parser.cpp ├── Parser.h ├── Scope.cpp ├── Scope.h ├── Token.cpp ├── Token.h ├── Types.h ├── VisitorInterface.h ├── main.cpp ├── signal.vcxproj ├── signal.vcxproj.filters ├── utils.cpp └── utils.h /.gitignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *.exe 3 | *.pdb 4 | *.obj 5 | *ipch* 6 | ipch/* 7 | *.tlog 8 | *.manifest 9 | *.ilk 10 | *.cache 11 | *.idb 12 | *.opensdf 13 | 14 | */Debug/* 15 | */Release/* 16 | Debug/* 17 | Release/* 18 | 19 | *.suo 20 | *.sdf 21 | *.user -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## signalscript 2 | 3 | This is a fork of [a scripting language](http://code.google.com/p/tibiasignal/source/browse/#svn/trunk) that an old friend of mine made back in 2010. 4 | 5 | The project got abandoned, and I made this fork just to get familiar with the code, add some small features, and learn about abstract syntax trees. 6 | 7 | 8 | 9 | ## What the language had when Jeremic dropped the project: 10 | * Fully working expressions. 11 | * Conditional if/else blocks. 12 | * Functions. 13 | * All binary operators except modulo, exponent, +=, and -=. 14 | * All unary operators except ++ and --. 15 | * Class parsing but no actual functionality. 16 | * Loop (while and for) parsing but no actual functionality. 17 | * Parsing of break and continue statements but no actual functionality. 18 | * Print() native function but no c-function exports. 19 | * Basic string, number, boolean, and nil types. 20 | 21 | 22 | ## What I've added in this fork: 23 | * Loop functionality (compilation and interpretation) for both while and for loops. 24 | * Functionality (compilation and interpretation) for both break and continue statements. 25 | * Class instance creation (via new operator). 26 | * Instance-level scoping for classes. 27 | * Member function calls for classes (parameters are acting up, though). 28 | * Unary operators ++ and -- (postfix). 29 | * String unescaping to support characters such as "\n" and "\t". 30 | * Many bug fixes with error reporting (std::strings were being passed into printf() as opposed to their .c_str() member calls). 31 | * Some changes to the overall structure of the architecture and virtual processor. 32 | * C++ function exporting 33 | * Switch statements (lexing, parsing, compilation, and interpretation). 34 | * Function keyword. 35 | * Improvements to many binary operators. 36 | * Numeric values which allow decimal places. 37 | * Optimizations / cleanups to the VM code. 38 | * Parsing and AST creation for tables (Currently no compilation or interpretation, though). 39 | 40 | 41 | ## What I want to add before I inevitably get tired of playing with the language: 42 | * Class members abstract the table interface (like in Lua). 43 | * Fix parameter bugs for class member functions. 44 | * Global variables. 45 | * Remaining binary operators (modulo, exponent, +=, and -=). 46 | 47 | 48 | ## Here's what the syntax/usage currently looks like (no class usage here, though, since it's pretty broken): 49 | 50 | function testWhile() 51 | { 52 | print("Expect 'haahaahaa'\n "); 53 | n = 0; 54 | while (true) 55 | { 56 | n = n + 1; 57 | print("h"); 58 | 59 | i = 0; 60 | while (i < 2) 61 | { 62 | i = i + 1; 63 | print("a"); 64 | } 65 | 66 | 67 | if (n == 3) 68 | break; 69 | else 70 | continue; 71 | } 72 | print("\n"); 73 | } 74 | 75 | 76 | function testFor() 77 | { 78 | print("Expect '012345 -- 54321 -- 13579'\n "); 79 | for (i = 0; i <= 5; i = i + 1) 80 | { 81 | print(i); 82 | } 83 | print(" -- "); 84 | for (i = 5; true; i = i - 1) 85 | { 86 | print(i); 87 | if (i == 1) 88 | break; 89 | } 90 | print(" -- "); 91 | for (i = 1; i < 10; i = i + 1) 92 | { 93 | if (i == 2 || i == 4 || i == 6 || i == 8) 94 | continue; 95 | print(i); 96 | } 97 | print("\n"); 98 | } 99 | 100 | 101 | function testIncDec() 102 | { 103 | print("Expect '01021 | -1 | 4'\n "); 104 | var = 0; 105 | print(var); 106 | 107 | 108 | var++; 109 | print(var); 110 | 111 | 112 | var--; 113 | print(var); 114 | 115 | 116 | var++;var++; 117 | print(var); 118 | 119 | 120 | var--; 121 | print(var); 122 | 123 | 124 | print(" | "); 125 | 126 | 127 | var--;var--; 128 | print(var); 129 | 130 | 131 | print(" | "); 132 | 133 | 134 | val = 1; 135 | val = val + val++; 136 | print(val); 137 | 138 | 139 | print("\n"); 140 | } 141 | 142 | 143 | function testSwitch(value) 144 | { 145 | switch (value) 146 | { 147 | case 3: 148 | print("three, "); 149 | case 2: 150 | { 151 | print("two, "); 152 | } 153 | case 1: 154 | { 155 | print("one\n"); 156 | break; 157 | } 158 | default: 159 | { 160 | print("other\n"); 161 | } 162 | } 163 | } 164 | 165 | 166 | function main() 167 | { 168 | testWhile(); 169 | testFor(); 170 | testIncDec(); 171 | 172 | 173 | print("Expect 'one'\n "); 174 | testSwitch(1); 175 | print("Expect 'two, one'\n "); 176 | testSwitch(2); 177 | print("Expect 'three, two, one'\n "); 178 | testSwitch(3); 179 | print("Expect 'other'\n "); 180 | testSwitch(4); 181 | } 182 | 183 | 184 | ## Here's the usage from C++: 185 | 186 | FileInput file (name); 187 | Lexer lexer (file); 188 | Parser parser (lexer); 189 | std::shared_ptr ast = parser.parse_program (); 190 | Environment env = Environment (); 191 | Compiler::Compile(env, ast); 192 | Interpreter interpreter(env); 193 | interpreter.execute (); 194 | 195 | ## Here's how you export a C++ function: 196 | 197 | //exported function prototype 198 | std::shared_ptr printFunc(Environment env, std::vector> args); 199 | 200 | //call this before Compiler::Compile(env, ast); 201 | env.exportFunction("print", printFunc); 202 | 203 | -------------------------------------------------------------------------------- /signal.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "signal", "signal\signal.vcxproj", "{8FA068BC-A38F-4B12-8937-EC79845C14BC}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {8FA068BC-A38F-4B12-8937-EC79845C14BC}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {8FA068BC-A38F-4B12-8937-EC79845C14BC}.Debug|Win32.Build.0 = Debug|Win32 14 | {8FA068BC-A38F-4B12-8937-EC79845C14BC}.Release|Win32.ActiveCfg = Release|Win32 15 | {8FA068BC-A38F-4B12-8937-EC79845C14BC}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /signal/AST.cpp: -------------------------------------------------------------------------------- 1 | #include "AST.h" 2 | 3 | namespace Signal 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /signal/AST.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Error.h" 7 | #include "Types.h" 8 | #include "Scope.h" 9 | #include "VisitorInterface.h" 10 | 11 | namespace Signal 12 | { 13 | class AST; 14 | class ASTClassDef; 15 | class ASTFuncDecl; 16 | class ASTMembDef; 17 | class ASTStatement; 18 | class ASTExpression; 19 | 20 | // Note all AST nodes are immutable and the constructors have move semantics, so be careful! 21 | 22 | class AST 23 | { 24 | public: 25 | 26 | AST (std::vector>& class_def, std::vector>& func_decl) 27 | { 28 | m_class_def.swap (class_def); 29 | m_func_decl.swap (func_decl); 30 | } 31 | 32 | void accept (VisitorInterface& visitor) const 33 | { 34 | visitor.visit (*this); 35 | } 36 | 37 | const std::vector>& class_def () const 38 | { 39 | return m_class_def; 40 | } 41 | 42 | const std::vector>& func_decl () const 43 | { 44 | return m_func_decl; 45 | } 46 | 47 | private: 48 | 49 | std::vector> m_class_def; 50 | std::vector> m_func_decl; 51 | }; 52 | 53 | class ASTClassDef 54 | { 55 | public: 56 | 57 | ASTClassDef (std::string& name, std::vector>& memb_def) 58 | { 59 | m_name.swap (name); 60 | m_memb_def.swap (memb_def); 61 | } 62 | 63 | ASTClassDef (std::string& name, std::string& base, std::vector>& memb_def) 64 | { 65 | m_name.swap (name); 66 | m_base.swap (base); 67 | m_memb_def.swap (memb_def); 68 | } 69 | 70 | const std::string& name () const 71 | { 72 | return m_name; 73 | } 74 | 75 | const std::string& base () const 76 | { 77 | return m_base; 78 | } 79 | 80 | const std::vector>& memb_def () const 81 | { 82 | return m_memb_def; 83 | } 84 | 85 | void accept (VisitorInterface& visitor) const 86 | { 87 | visitor.visit(*this); 88 | } 89 | 90 | private: 91 | 92 | std::string m_name; 93 | std::string m_base; 94 | 95 | std::vector> m_memb_def; 96 | }; 97 | 98 | class ASTFuncDecl 99 | { 100 | public: 101 | 102 | const std::string& name () const 103 | { 104 | return m_name; 105 | } 106 | 107 | const std::vector& args () const 108 | { 109 | return m_args; 110 | } 111 | 112 | const std::shared_ptr& body () const 113 | { 114 | return m_body; 115 | } 116 | 117 | virtual void accept (VisitorInterface& visitor) const 118 | { 119 | throw Error ("AST : Invalid ast."); 120 | } 121 | 122 | protected: 123 | 124 | std::string m_name; 125 | 126 | std::vector m_args; 127 | std::shared_ptr m_body; 128 | }; 129 | 130 | class ASTMFuncDecl : public ASTFuncDecl 131 | { 132 | public: 133 | 134 | ASTMFuncDecl (std::string& name, std::string& base, std::vector& args, std::shared_ptr body) 135 | { 136 | m_name.swap (name); 137 | m_base.swap (base); 138 | m_args.swap (args); 139 | m_body = body; 140 | } 141 | 142 | const std::string& base () const 143 | { 144 | return m_base; 145 | } 146 | 147 | void accept (VisitorInterface& visitor) const 148 | { 149 | visitor.visit (*this); 150 | } 151 | 152 | private: 153 | 154 | std::string m_base; 155 | }; 156 | 157 | class ASTGFuncDecl : public ASTFuncDecl 158 | { 159 | public: 160 | 161 | ASTGFuncDecl (std::string& name, std::vector& args, std::shared_ptr body) 162 | { 163 | m_name.swap (name); 164 | m_args.swap (args); 165 | m_body = body; 166 | } 167 | 168 | void accept (VisitorInterface& visitor) const 169 | { 170 | visitor.visit (*this); 171 | } 172 | }; 173 | 174 | class ASTMembDef 175 | { 176 | public: 177 | 178 | virtual void accept (VisitorInterface& visitor, std::shared_ptr _class) const 179 | { 180 | throw Error ("AST : Invalid ast."); 181 | } 182 | 183 | protected: 184 | 185 | std::string m_name; 186 | }; 187 | 188 | class ASTVarDef : public ASTMembDef 189 | { 190 | public: 191 | 192 | ASTVarDef (std::string& name) 193 | { 194 | m_name.swap (name); 195 | } 196 | 197 | const std::string& name () const 198 | { 199 | return m_name; 200 | } 201 | 202 | void accept (VisitorInterface& visitor, std::shared_ptr _class) const 203 | { 204 | visitor.visit (*this, _class); 205 | } 206 | }; 207 | 208 | class ASTFuncDef : public ASTMembDef 209 | { 210 | public: 211 | 212 | ASTFuncDef (std::string& name, std::vector& args) 213 | { 214 | m_name.swap (name); 215 | m_args.swap (args); 216 | } 217 | 218 | const std::string& name () const 219 | { 220 | return m_name; 221 | } 222 | 223 | const std::vector& args () const 224 | { 225 | return m_args; 226 | } 227 | 228 | void accept (VisitorInterface& visitor, std::shared_ptr _class) const 229 | { 230 | visitor.visit (*this, _class); 231 | } 232 | 233 | private: 234 | 235 | std::vector m_args; 236 | }; 237 | 238 | class ASTStatement 239 | { 240 | public: 241 | 242 | virtual ~ASTStatement () {} 243 | 244 | virtual void accept (VisitorInterface& visitor, std::shared_ptr func) const = 0; 245 | }; 246 | 247 | class ASTBlock : public ASTStatement 248 | { 249 | public: 250 | 251 | ASTBlock (std::vector>& block) 252 | { 253 | m_block.swap (block); 254 | } 255 | 256 | const std::vector>& stmts () const 257 | { 258 | return m_block; 259 | } 260 | 261 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 262 | { 263 | visitor.visit (*this, func); 264 | } 265 | 266 | private: 267 | 268 | std::vector> m_block; 269 | }; 270 | 271 | class ASTIf : public ASTStatement 272 | { 273 | public: 274 | 275 | ASTIf (std::shared_ptr cond, std::shared_ptr if_part) 276 | : 277 | m_cond (cond), 278 | m_if_part (if_part) 279 | {} 280 | 281 | ASTIf (std::shared_ptr cond, std::shared_ptr if_part, std::shared_ptr else_part) 282 | : 283 | m_cond (cond), 284 | m_if_part (if_part), 285 | m_else_part (else_part) 286 | {} 287 | 288 | std::shared_ptr cond () const 289 | { 290 | return m_cond; 291 | } 292 | 293 | std::shared_ptr if_part () const 294 | { 295 | return m_if_part; 296 | } 297 | 298 | std::shared_ptr else_part () const 299 | { 300 | return m_else_part; 301 | } 302 | 303 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 304 | { 305 | visitor.visit (*this, func); 306 | } 307 | 308 | private: 309 | 310 | std::shared_ptr m_cond; 311 | std::shared_ptr m_if_part; 312 | std::shared_ptr m_else_part; 313 | }; 314 | 315 | class ASTWhile : public ASTStatement 316 | { 317 | public: 318 | 319 | ASTWhile (std::shared_ptr cond, std::shared_ptr body) 320 | : 321 | m_cond (cond), 322 | m_body (body) 323 | {} 324 | 325 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 326 | { 327 | visitor.visit (*this, func); 328 | } 329 | 330 | std::shared_ptr cond() const 331 | { 332 | return m_cond; 333 | } 334 | 335 | std::shared_ptr body() const 336 | { 337 | return m_body; 338 | } 339 | 340 | private: 341 | 342 | std::shared_ptr m_cond; 343 | std::shared_ptr m_body; 344 | }; 345 | 346 | class ASTFor : public ASTStatement 347 | { 348 | public: 349 | 350 | ASTFor (std::shared_ptr init, std::shared_ptr cond, std::shared_ptr inc, std::shared_ptr body) 351 | : 352 | m_init (init), 353 | m_cond (cond), 354 | m_inc (inc), 355 | m_body (body) 356 | {} 357 | 358 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 359 | { 360 | visitor.visit (*this, func); 361 | } 362 | 363 | std::shared_ptr init() const 364 | { 365 | return m_init; 366 | } 367 | 368 | std::shared_ptr cond() const 369 | { 370 | return m_cond; 371 | } 372 | 373 | std::shared_ptr inc() const 374 | { 375 | return m_inc; 376 | } 377 | 378 | std::shared_ptr body() const 379 | { 380 | return m_body; 381 | } 382 | 383 | private: 384 | 385 | std::shared_ptr m_init; 386 | std::shared_ptr m_cond; 387 | std::shared_ptr m_inc; 388 | std::shared_ptr m_body; 389 | }; 390 | 391 | class ASTSwitch : public ASTStatement 392 | { 393 | public: 394 | 395 | ASTSwitch(std::shared_ptr expr) 396 | : m_expr(expr) 397 | {} 398 | 399 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 400 | { 401 | visitor.visit (*this, func); 402 | } 403 | 404 | std::shared_ptr expr() const 405 | { 406 | return m_expr; 407 | } 408 | 409 | std::vector, std::shared_ptr>> cases() const 410 | { 411 | return m_cases; 412 | } 413 | 414 | void addCase(std::shared_ptr indetifier, std::shared_ptr statement) 415 | { 416 | m_cases.push_back(std::make_pair, std::shared_ptr>(indetifier, statement)); 417 | } 418 | 419 | private: 420 | std::shared_ptr m_expr; 421 | std::vector, std::shared_ptr>> m_cases; 422 | }; 423 | 424 | class ASTBreak : public ASTStatement 425 | { 426 | public: 427 | 428 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 429 | { 430 | visitor.visit (*this, func); 431 | } 432 | }; 433 | 434 | class ASTContinue : public ASTStatement 435 | { 436 | public: 437 | 438 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 439 | { 440 | visitor.visit (*this, func); 441 | } 442 | }; 443 | 444 | class ASTReturn : public ASTStatement 445 | { 446 | public: 447 | 448 | ASTReturn (std::shared_ptr ret) 449 | : 450 | m_ret (ret) 451 | {} 452 | 453 | std::shared_ptr ret () const 454 | { 455 | return m_ret; 456 | } 457 | 458 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 459 | { 460 | visitor.visit (*this, func); 461 | } 462 | 463 | private: 464 | 465 | std::shared_ptr m_ret; 466 | }; 467 | 468 | class ASTStmtExpr : public ASTStatement 469 | { 470 | public: 471 | 472 | ASTStmtExpr (std::shared_ptr expr) 473 | : 474 | m_expr (expr) 475 | {} 476 | 477 | const std::shared_ptr expr () const 478 | { 479 | return m_expr; 480 | } 481 | 482 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 483 | { 484 | visitor.visit (*this, func); 485 | } 486 | 487 | private: 488 | 489 | std::shared_ptr m_expr; 490 | }; 491 | 492 | class ASTExpression 493 | { 494 | public: 495 | 496 | enum Type 497 | { 498 | NONE, 499 | ASSIGNMENT, 500 | COMPARE, 501 | IDENTIFIER, 502 | NUMBER, 503 | STRING, 504 | NIL, 505 | TRUE, 506 | FALSE 507 | }; 508 | 509 | ASTExpression () {} 510 | ASTExpression (std::vector>& exprs) 511 | { 512 | m_exprs.swap (exprs); 513 | } 514 | 515 | virtual Type type () const 516 | { 517 | return ASTExpression::NONE; 518 | } 519 | 520 | const std::vector>& exprs () const 521 | { 522 | return m_exprs; 523 | } 524 | 525 | virtual void accept (VisitorInterface& visitor, std::shared_ptr func) const 526 | { 527 | visitor.visit (*this, func); 528 | } 529 | 530 | private: 531 | 532 | std::vector> m_exprs; 533 | }; 534 | 535 | class ASTAssignment : public ASTExpression 536 | { 537 | public: 538 | 539 | ASTAssignment (std::string& var, std::shared_ptr expr) 540 | : 541 | m_expr (expr) 542 | { 543 | m_var.swap (var); 544 | } 545 | 546 | ASTExpression::Type type () const 547 | { 548 | return ASTExpression::ASSIGNMENT; 549 | } 550 | 551 | const std::string& var () const 552 | { 553 | return m_var; 554 | } 555 | 556 | std::shared_ptr expr () const 557 | { 558 | return m_expr; 559 | } 560 | 561 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 562 | { 563 | visitor.visit (*this, func); 564 | } 565 | 566 | private: 567 | 568 | std::string m_var; 569 | std::shared_ptr m_expr; 570 | }; 571 | 572 | class ASTCompare : public ASTExpression 573 | { 574 | public: 575 | 576 | enum OpType 577 | { 578 | OR, 579 | AND, 580 | EQUALS_EQUALS, 581 | NOT_EQUALS, 582 | LESS_THAN, 583 | GREATER_THAN, 584 | LESS_THAN_EQUALS, 585 | GREATER_THAN_EQUALS, 586 | }; 587 | 588 | ASTCompare (OpType type, std::shared_ptr left, std::shared_ptr right) 589 | : 590 | m_left (left), 591 | m_right (right), 592 | m_type (type) 593 | {} 594 | 595 | std::shared_ptr left () const 596 | { 597 | return m_left; 598 | } 599 | 600 | std::shared_ptr right () const 601 | { 602 | return m_right; 603 | } 604 | 605 | OpType op_type () const 606 | { 607 | return m_type; 608 | } 609 | 610 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 611 | { 612 | visitor.visit (*this, func); 613 | } 614 | 615 | private: 616 | 617 | OpType m_type; 618 | 619 | std::shared_ptr m_left; 620 | std::shared_ptr m_right; 621 | }; 622 | 623 | class ASTBinaryMathOp : public ASTExpression 624 | { 625 | public: 626 | 627 | enum OpType 628 | { 629 | PLUS, 630 | MINUS, 631 | TIMES, 632 | DIVIDE 633 | }; 634 | 635 | class ASTBinaryMathOp (OpType type, std::shared_ptr left, std::shared_ptr right) 636 | : 637 | m_left (left), 638 | m_right (right), 639 | m_type (type) 640 | {} 641 | 642 | std::shared_ptr left () const 643 | { 644 | return m_left; 645 | } 646 | 647 | std::shared_ptr right () const 648 | { 649 | return m_right; 650 | } 651 | 652 | OpType op_type () const 653 | { 654 | return m_type; 655 | } 656 | 657 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 658 | { 659 | visitor.visit (*this, func); 660 | } 661 | 662 | private: 663 | 664 | OpType m_type; 665 | 666 | std::shared_ptr m_left; 667 | std::shared_ptr m_right; 668 | }; 669 | 670 | class ASTUnaryMathOp : public ASTExpression 671 | { 672 | public: 673 | 674 | enum OpType 675 | { 676 | MINUS, 677 | NOT, 678 | INCREMENT, 679 | DECREMENT 680 | }; 681 | 682 | class ASTUnaryMathOp (OpType type, std::shared_ptr expr) 683 | : 684 | m_expr (expr), 685 | m_type (type) 686 | {} 687 | 688 | std::shared_ptr expr () const 689 | { 690 | return m_expr; 691 | } 692 | 693 | OpType op_type () const 694 | { 695 | return m_type; 696 | } 697 | 698 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 699 | { 700 | visitor.visit (*this, func); 701 | } 702 | 703 | private: 704 | 705 | OpType m_type; 706 | 707 | std::shared_ptr m_expr; 708 | }; 709 | 710 | class ASTNew : public ASTExpression 711 | { 712 | public: 713 | 714 | ASTNew (std::string& name, std::vector>& args) 715 | { 716 | m_name.swap (name); 717 | m_args.swap (args); 718 | } 719 | 720 | const std::string& name () const 721 | { 722 | return m_name; 723 | } 724 | 725 | const std::vector>& args () const 726 | { 727 | return m_args; 728 | } 729 | 730 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 731 | { 732 | visitor.visit (*this, func); 733 | } 734 | 735 | private: 736 | 737 | std::string m_name; 738 | std::vector> m_args; 739 | }; 740 | 741 | class ASTFuncCall : public ASTExpression 742 | { 743 | public: 744 | 745 | virtual void accept (VisitorInterface& visitor, std::shared_ptr func) const = 0; 746 | 747 | protected: 748 | 749 | std::string m_name; 750 | std::vector> m_args; 751 | }; 752 | 753 | class ASTGFuncCall : public ASTFuncCall 754 | { 755 | public: 756 | 757 | ASTGFuncCall (std::string& name, std::vector>& args) 758 | { 759 | m_name.swap (name); 760 | m_args.swap (args); 761 | } 762 | 763 | const std::string& name () const 764 | { 765 | return m_name; 766 | } 767 | 768 | const std::vector>& args () const 769 | { 770 | return m_args; 771 | } 772 | 773 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 774 | { 775 | visitor.visit (*this, func); 776 | } 777 | }; 778 | 779 | class ASTMFuncCall : public ASTFuncCall 780 | { 781 | public: 782 | 783 | ASTMFuncCall (std::string& name, std::string& base, std::vector>& args) 784 | { 785 | m_name.swap (name); 786 | m_base.swap (base); 787 | m_args.swap (args); 788 | } 789 | 790 | const std::string& name () const 791 | { 792 | return m_name; 793 | } 794 | 795 | const std::vector>& args () const 796 | { 797 | return m_args; 798 | } 799 | 800 | const std::string& base () const 801 | { 802 | return m_base; 803 | } 804 | 805 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 806 | { 807 | visitor.visit (*this, func); 808 | } 809 | 810 | private: 811 | 812 | std::string m_base; 813 | }; 814 | 815 | class ASTIdentifier : public ASTExpression 816 | { 817 | public: 818 | 819 | ASTIdentifier (std::string& name) 820 | { 821 | m_name.swap (name); 822 | } 823 | 824 | ASTIdentifier (std::string&& name) 825 | { 826 | m_name.swap (name); 827 | } 828 | 829 | Type type () const 830 | { 831 | return ASTExpression::IDENTIFIER; 832 | } 833 | 834 | std::string name () const 835 | { 836 | return m_name; 837 | } 838 | 839 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 840 | { 841 | visitor.visit (*this, func); 842 | } 843 | 844 | private: 845 | 846 | std::string m_name; 847 | }; 848 | 849 | class ASTNumber : public ASTExpression 850 | { 851 | public: 852 | 853 | ASTNumber (double_t val) 854 | : 855 | m_val (val) 856 | {} 857 | 858 | double_t value () const 859 | { 860 | return m_val; 861 | } 862 | 863 | Type type () const 864 | { 865 | return ASTExpression::NUMBER; 866 | } 867 | 868 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 869 | { 870 | visitor.visit (*this, func); 871 | } 872 | 873 | private: 874 | 875 | double_t m_val; 876 | }; 877 | 878 | class ASTString : public ASTExpression 879 | { 880 | public: 881 | 882 | ASTString (std::string& text) 883 | { 884 | m_text.swap (text); 885 | } 886 | 887 | ASTString (std::string&& text) 888 | { 889 | m_text.swap (text); 890 | } 891 | 892 | Type type () const 893 | { 894 | return ASTExpression::STRING; 895 | } 896 | 897 | const std::string& text () const 898 | { 899 | return m_text; 900 | } 901 | 902 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 903 | { 904 | visitor.visit (*this, func); 905 | } 906 | 907 | private: 908 | 909 | std::string m_text; 910 | }; 911 | 912 | class ASTNil : public ASTExpression 913 | { 914 | public: 915 | 916 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 917 | { 918 | visitor.visit (*this, func); 919 | } 920 | }; 921 | 922 | class ASTTrue : public ASTExpression 923 | { 924 | public: 925 | 926 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 927 | { 928 | visitor.visit (*this, func); 929 | } 930 | }; 931 | 932 | class ASTFalse : public ASTExpression 933 | { 934 | public: 935 | 936 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 937 | { 938 | visitor.visit (*this, func); 939 | } 940 | }; 941 | 942 | class ASTTable : public ASTExpression 943 | { 944 | public: 945 | 946 | void accept (VisitorInterface& visitor, std::shared_ptr func) const 947 | { 948 | visitor.visit (*this, func); 949 | } 950 | 951 | bool insertValue(std::shared_ptr key, std::shared_ptr value) 952 | { 953 | if (key == nullptr) //no key set, use first open index 954 | { 955 | m_autoIntegerValues[m_autoIntegerValues.size()] = value; 956 | return true; 957 | } 958 | else //key set, let's figure out what we're doing 959 | { 960 | if (key->type() == ASTExpression::NUMBER) 961 | { 962 | auto ikey = dynamic_cast(key.get()); 963 | if (m_integerValues.find(ikey->value()) != m_integerValues.end()) 964 | return false; 965 | m_integerValues[ikey->value()] = value; 966 | } 967 | else if (key->type() == ASTExpression::STRING) 968 | { 969 | auto tkey = dynamic_cast(key.get()); 970 | if (m_stringValues.find(tkey->text()) != m_stringValues.end()) 971 | return false; 972 | m_stringValues[tkey->text()] = value; 973 | } 974 | else if (key->type() == ASTExpression::IDENTIFIER) 975 | { 976 | auto ikey = dynamic_cast(key.get()); 977 | if (m_stringValues.find(ikey->name()) != m_stringValues.end()) 978 | return false; 979 | m_stringValues[ikey->name()] = value; 980 | } 981 | else 982 | return false; 983 | return true; 984 | } 985 | return false; 986 | } 987 | 988 | void normalizeValues() 989 | { 990 | //we insert all of the values that were specified without keys at the first open integer indexes 991 | for (auto kvp = m_autoIntegerValues.begin(); kvp != m_autoIntegerValues.end(); kvp++) 992 | { 993 | for (uint32_t i = 0; true; i++) 994 | { 995 | if (m_integerValues.find(i) == m_integerValues.end()) 996 | { 997 | m_integerValues[i] = kvp->second; 998 | break; 999 | } 1000 | } 1001 | } 1002 | m_autoIntegerValues.clear(); 1003 | 1004 | std::cout << "-------------------" << std::endl; 1005 | for (auto kvp = m_stringValues.begin(); kvp != m_stringValues.end(); kvp++) 1006 | { 1007 | std::cout << "[" << kvp->first << "] "; 1008 | if (kvp->second->type() == ASTExpression::NUMBER) 1009 | { 1010 | auto ikey = dynamic_cast(kvp->second.get()); 1011 | std::cout << "(number) " << ikey->value(); 1012 | } 1013 | else if (kvp->second->type() == ASTExpression::STRING) 1014 | { 1015 | auto tkey = dynamic_cast(kvp->second.get()); 1016 | std::cout << "(string) " << tkey->text(); 1017 | } 1018 | else if (kvp->second->type() == ASTExpression::IDENTIFIER) 1019 | { 1020 | auto ikey = dynamic_cast(kvp->second.get()); 1021 | std::cout << "(iden) " << ikey->name(); 1022 | } 1023 | else 1024 | std::cout << kvp->second->type(); 1025 | std::cout << std::endl; 1026 | } 1027 | 1028 | for (auto kvp = m_integerValues.begin(); kvp != m_integerValues.end(); kvp++) 1029 | { 1030 | std::cout << "[" << kvp->first << "] "; 1031 | if (kvp->second->type() == ASTExpression::NUMBER) 1032 | { 1033 | auto ikey = dynamic_cast(kvp->second.get()); 1034 | std::cout << "(number) " << ikey->value(); 1035 | } 1036 | else if (kvp->second->type() == ASTExpression::STRING) 1037 | { 1038 | auto tkey = dynamic_cast(kvp->second.get()); 1039 | std::cout << "(string) " << tkey->text(); 1040 | } 1041 | else if (kvp->second->type() == ASTExpression::IDENTIFIER) 1042 | { 1043 | auto ikey = dynamic_cast(kvp->second.get()); 1044 | std::cout << "(iden) " << ikey->name(); 1045 | } 1046 | else 1047 | std::cout << kvp->second->type(); 1048 | std::cout << std::endl; 1049 | } 1050 | } 1051 | 1052 | private: 1053 | 1054 | std::map> m_stringValues; 1055 | std::map> m_integerValues; 1056 | std::map> m_autoIntegerValues; 1057 | 1058 | }; 1059 | } -------------------------------------------------------------------------------- /signal/Code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Types.h" 6 | 7 | namespace Signal 8 | { 9 | class Object; 10 | class Scope; 11 | 12 | enum OpCode 13 | { 14 | OP_PUSH, // Push object onto top of stack 15 | OP_POP, // Pop object back from top of stack 16 | OP_NIL, // Push Nil onto stack 17 | 18 | OP_CALL, // Call a function 19 | OP_MCALL, // Call a member function 20 | OP_RETURN, // Return from a function call, a return value is on top of the stack 21 | OP_ECALL, // Call exported function 22 | 23 | OP_SET, // Sets variable to object on top of the stack 24 | OP_DEF, // Defines a variable and sets it to object on top of the stack 25 | OP_REF, // References a variable to the stack 26 | 27 | OP_BR, // Branch unconditionally 28 | OP_BRT, // If top of the stack has True then branch 29 | OP_BRF, // If top of the stack has False then branch 30 | 31 | OP_ADD, // Add two objects from top of stack, and push the answer to the stack 32 | OP_SUB, // Subtract two objects from top of stack, and push the answer to the stack 33 | OP_MUL, // Multiply two objects from top of stack, and push the answer to the stack 34 | OP_DIV, // Divide two objects from top of stack, and push the answer to the stack 35 | OP_NEG, // Negate the top of the stack 36 | 37 | OP_INC, // Increment the object on top of the stack 38 | OP_DEC, // Decrement the object on top of the stack 39 | 40 | OP_NOT, // Logical not the top of the stack 41 | OP_OR, // Or two objects from top of stack, and push the answer to the stack 42 | OP_AND, // And two objects from top of stack, and push the answer to the stack 43 | OP_EQEQ, // Compare two objects from top of stack, and push the boolean answer to the stack 44 | OP_NEQ, // Compare two objects from top of stack, and push the boolean answer to the stack 45 | OP_LT, // Compare two objects from top of stack, and push the boolean answer to the stack 46 | OP_GT, // Compare two objects from top of stack, and push the boolean answer to the stack 47 | OP_LTE, // Compare two objects from top of stack, and push the boolean answer to the stack 48 | OP_GTE // Compare two objects from top of stack, and push the boolean answer to the stack 49 | }; 50 | 51 | struct Instruction 52 | { 53 | Instruction (OpCode op) 54 | : 55 | m_op (op) 56 | {} 57 | 58 | Instruction (OpCode op, uint32_t arg) 59 | : 60 | m_op (op), 61 | m_arg (arg) 62 | {} 63 | 64 | Instruction (OpCode op, std::shared_ptr object) 65 | : 66 | m_op (op), 67 | m_object (object) 68 | {} 69 | 70 | Instruction (OpCode op, std::shared_ptr scope) 71 | : 72 | m_op (op), 73 | m_scope (scope) 74 | {} 75 | 76 | Instruction (OpCode op, std::shared_ptr scope, std::shared_ptr object) 77 | : 78 | m_op (op), 79 | m_scope (scope), 80 | m_object (object) 81 | {} 82 | 83 | Instruction (OpCode op, uint32_t arg, std::shared_ptr object) 84 | : 85 | m_op (op), 86 | m_arg (arg), 87 | m_object (object) 88 | {} 89 | 90 | OpCode m_op; 91 | uint32_t m_arg; 92 | 93 | std::shared_ptr m_scope; 94 | std::shared_ptr m_object; 95 | }; 96 | 97 | class CodeBlock 98 | { 99 | public: 100 | 101 | CodeBlock () {} 102 | 103 | void write(OpCode op) 104 | { 105 | m_instructions.push_back (Instruction (op)); 106 | } 107 | 108 | void write(OpCode op, uint32_t arg) 109 | { 110 | m_instructions.push_back (Instruction (op, arg)); 111 | } 112 | 113 | void write(OpCode op, std::shared_ptr object) 114 | { 115 | m_instructions.push_back (Instruction (op, object)); 116 | } 117 | 118 | void write(OpCode op, std::shared_ptr scope) 119 | { 120 | m_instructions.push_back (Instruction (op, scope)); 121 | } 122 | 123 | void write(OpCode op, std::shared_ptr scope, std::shared_ptr object) 124 | { 125 | m_instructions.push_back (Instruction (op, scope, object)); 126 | } 127 | 128 | void write(OpCode op, uint32_t arg, std::shared_ptr object) 129 | { 130 | m_instructions.push_back (Instruction (op, arg, object)); 131 | } 132 | 133 | Instruction& operator[] (uint32_t i) 134 | { 135 | return m_instructions[i]; 136 | } 137 | 138 | uint32_t count () const 139 | { 140 | return m_instructions.size (); 141 | } 142 | 143 | private: 144 | 145 | std::vector m_instructions; 146 | }; 147 | } -------------------------------------------------------------------------------- /signal/Compiler.cpp: -------------------------------------------------------------------------------- 1 | #include "Compiler.h" 2 | 3 | namespace Signal 4 | { 5 | void Compiler::Compile (Environment& env, std::shared_ptr ast) 6 | { 7 | Compiler compiler = Compiler(env); 8 | 9 | compiler.visit (*ast); 10 | } 11 | 12 | Compiler::Compiler (Environment& env) 13 | : 14 | m_env (env) 15 | {} 16 | 17 | void Compiler::visit (const AST& ast) 18 | { 19 | const std::vector>& class_def = ast.class_def (); 20 | const std::vector>& func_decl = ast.func_decl (); 21 | 22 | for (uint32_t i = 0; i < class_def.size (); i++) { 23 | class_def[i]->accept (*this); 24 | } 25 | 26 | for (uint32_t i = 0; i < func_decl.size (); i++) { 27 | func_decl[i]->accept (*this); 28 | } 29 | } 30 | 31 | void Compiler::visit (const ASTClassDef& class_def) 32 | { 33 | const std::string name = class_def.name(); 34 | const std::string base_name = class_def.base (); 35 | 36 | std::shared_ptr new_class; 37 | 38 | if (base_name.length () == 0) { 39 | new_class = std::shared_ptr (new Class(name)); 40 | } else { 41 | std::shared_ptr base = m_env.find_class (base_name); 42 | 43 | if (base.get () == nullptr) { 44 | ThrowCompileError("Compiler : Base class '%s' has not been defined.", base_name.c_str ()); 45 | } 46 | 47 | new_class = std::shared_ptr (new Class(name, base)); 48 | } 49 | 50 | m_env.add_class (new_class); 51 | const std::vector>& memb_def = class_def.memb_def(); 52 | 53 | for (uint32_t i = 0; i < memb_def.size (); i++) { 54 | memb_def[i]->accept (*this, new_class); 55 | } 56 | } 57 | 58 | void Compiler::visit (const ASTMFuncDecl& func_decl) 59 | { 60 | std::shared_ptr _class = m_env.find_class(func_decl.base()); 61 | 62 | if (_class.get () == nullptr) { 63 | ThrowCompileError("Compiler : Class '%s' does not exist.", func_decl.base().c_str ()); 64 | } 65 | 66 | std::shared_ptr func = _class->find_func(func_decl.name()); 67 | 68 | if (func.get () == nullptr) { 69 | ThrowCompileError("Compiler : Class '%s' does not define the function '%s'.", func_decl.base ().c_str (), func_decl.name().c_str()); 70 | } 71 | 72 | for (int32_t i = func_decl.args ().size () - 1; i >= 0; i--) { 73 | func->code()->write (OP_SET, std::shared_ptr (new String (func_decl.args()[i]))); 74 | func->code()->write (OP_POP); 75 | } 76 | 77 | if (func_decl.body().get() != nullptr) { 78 | func_decl.body()->accept (*this, func); 79 | 80 | // We add this in case the user explicitly doesn't return anything in which case the function is void. 81 | func->code ()->write (OP_PUSH, m_env.obj_nil()); 82 | func->code ()->write (OP_RETURN); 83 | } 84 | } 85 | 86 | void Compiler::visit (const ASTGFuncDecl& func_decl) 87 | { 88 | std::shared_ptr new_func (new Function (func_decl.name(), func_decl.args ())); 89 | m_env.add_func(new_func); 90 | 91 | for (int32_t i = func_decl.args ().size () - 1; i >= 0; i--) { 92 | new_func->code ()->write (OP_SET, std::shared_ptr(new String(func_decl.args()[i]))); 93 | new_func->code ()->write (OP_POP); 94 | } 95 | 96 | if (func_decl.body ().get () != nullptr) { 97 | func_decl.body ()->accept (*this, new_func); 98 | 99 | // We add this in case the user explicitly doesn't return anything in which case the function is void. 100 | new_func->code()->write (OP_PUSH, m_env.obj_nil ()); 101 | new_func->code()->write (OP_RETURN); 102 | } 103 | } 104 | 105 | void Compiler::visit (const ASTVarDef& var_def, std::shared_ptr _class) 106 | { 107 | std::shared_ptr scope = _class->scope (); 108 | scope->define (var_def.name()); 109 | } 110 | 111 | void Compiler::visit (const ASTFuncDef& func_def, std::shared_ptr _class) 112 | { 113 | std::shared_ptr func (new Function (func_def.name(), func_def.args ())); 114 | _class->add_func (func); 115 | } 116 | 117 | void Compiler::visit (const ASTBlock& block, std::shared_ptr func) 118 | { 119 | const std::vector>& stmts = block.stmts (); 120 | 121 | for (uint32_t i = 0; i < stmts.size (); i++) { 122 | stmts[i]->accept (*this, func); 123 | } 124 | } 125 | 126 | void Compiler::visit (const ASTIf& if_stmt, std::shared_ptr func) 127 | { 128 | std::shared_ptr code = func->code (); 129 | 130 | // Compile the condition 131 | if_stmt.cond ()->accept (*this, func); 132 | 133 | // If its false branch past the if part 134 | code->write (OP_BRF, 0); 135 | uint32_t index = code->count () - 1; 136 | 137 | // Compile the if part 138 | if_stmt.if_part ()->accept (*this, func); 139 | 140 | // We set the offset after we compile the if part 141 | Instruction& brf = (*code)[index]; 142 | brf.m_arg = code->count (); 143 | 144 | if (if_stmt.else_part().get () != nullptr) 145 | if_stmt.else_part()->accept (*this, func); 146 | } 147 | 148 | void Compiler::visit (const ASTWhile& while_stmt, std::shared_ptr func) 149 | { 150 | std::shared_ptr code = func->code(); 151 | 152 | // do conition 153 | uint32_t cond = code->count(); 154 | while_stmt.cond()->accept(*this, func); 155 | 156 | // branch out if condition is false 157 | code->write(OP_BRF, 0); 158 | uint32_t condBranch = code->count() - 1; 159 | 160 | // compile the body 161 | while_stmt.body()->accept(*this, func); 162 | 163 | // branch back to the condition 164 | code->write(OP_BR, cond); 165 | uint32_t end = code->count(); 166 | 167 | // set the conditional branch offset 168 | Instruction& brf = (*code)[condBranch]; 169 | brf.m_arg = end; 170 | 171 | // fill breaks/continues 172 | for (uint32_t i = cond; i < end; i++) 173 | { 174 | Instruction& inst = (*code)[i]; 175 | if (inst.m_op == OP_BR && inst.m_arg == 0xDEADBEEF) // break, jump to end 176 | inst.m_arg = end; 177 | else if (inst.m_op == OP_BR && inst.m_arg == 0xFEEDBEAD) //continue, jump to condition 178 | inst.m_arg = cond; 179 | } 180 | } 181 | 182 | void Compiler::visit (const ASTFor& for_stmt, std::shared_ptr func) 183 | { 184 | std::shared_ptr code = func->code(); 185 | 186 | // init the loop variables 187 | uint32_t init = code->count(); 188 | for_stmt.init()->accept(*this, func); 189 | 190 | // do conition 191 | uint32_t cond = code->count(); 192 | for_stmt.cond()->accept(*this, func); 193 | 194 | // branch out if condition is false 195 | code->write(OP_BRF, 0); 196 | uint32_t condition = code->count() - 1; 197 | 198 | // compile the body 199 | for_stmt.body()->accept(*this, func); 200 | 201 | // increment condition 202 | uint32_t inc = code->count(); 203 | for_stmt.inc()->accept(*this, func); 204 | 205 | // branch back to the condition 206 | code->write(OP_BR, cond); 207 | uint32_t end = code->count(); 208 | 209 | // set the conditional branch offset 210 | Instruction& brf = (*code)[condition]; 211 | brf.m_arg = end; 212 | 213 | // fill breaks/continues 214 | for (uint32_t i = cond; i < end; i++) 215 | { 216 | Instruction& inst = (*code)[i]; 217 | if (inst.m_op == OP_BR && inst.m_arg == 0xDEADBEEF) // break, jump to end 218 | inst.m_arg = end; 219 | else if (inst.m_op == OP_BR && inst.m_arg == 0xFEEDBEAD) //continue, jump to increment 220 | inst.m_arg = inc; 221 | } 222 | } 223 | 224 | void Compiler::visit (const ASTSwitch& switch_stmt, std::shared_ptr func) 225 | { 226 | auto code = func->code(); 227 | auto cases = switch_stmt.cases(); 228 | auto switchObj = std::shared_ptr(new String("[-switch-]")); 229 | 230 | // eval our first expression, set it to variable "--switch--" 231 | switch_stmt.expr()->accept(*this, func); 232 | code->write(OP_DEF, switchObj); 233 | 234 | // create our jump table 235 | uint32_t startJmpTable = code->count(); 236 | bool defaultCase = false; 237 | for (uint32_t i = 0; i < cases.size(); i++) 238 | { 239 | if (cases[i].first.get() == nullptr) //default case, should come last 240 | defaultCase = true; 241 | else 242 | { 243 | cases[i].first->accept(*this, func); //eval the comparison expression 244 | code->write(OP_REF, switchObj); //reference our switch variable 245 | code->write(OP_EQEQ); //compare them 246 | code->write(OP_BRT, 0xBEADFEED); //branch if true to the actual code block 247 | } 248 | } 249 | uint32_t endJmpTable = code->count(); 250 | code->write(OP_BR, 0); 251 | 252 | // write each case block 253 | uint32_t startBlocks = code->count(); 254 | uint32_t lastBlock = 0; 255 | for (uint32_t i = 0; i < cases.size(); i++) 256 | { 257 | // find the branch for this block (will be the first one) and write this blocks address 258 | for (int32_t j = startJmpTable; j < endJmpTable; j++) 259 | { 260 | Instruction& inst = (*code)[j]; 261 | if (inst.m_op == OP_BRT && inst.m_arg == 0xBEADFEED) 262 | { 263 | inst.m_arg = code->count(); 264 | break; 265 | } 266 | } 267 | 268 | if (cases[i].second.get() == nullptr) // fallthrough 269 | continue; 270 | 271 | lastBlock = code->count(); 272 | cases[i].second->accept(*this, func); // do the block 273 | } 274 | uint32_t endBlocks = code->count(); 275 | 276 | // set up our final branch incase we had no default statement 277 | Instruction& last = (*code)[endJmpTable]; 278 | if (defaultCase) 279 | last.m_arg = lastBlock; 280 | else 281 | last.m_arg = endBlocks; 282 | 283 | // fill breaks/continues 284 | for (uint32_t i = startBlocks; i < endBlocks; i++) 285 | { 286 | Instruction& inst = (*code)[i]; 287 | if (inst.m_op == OP_BR && inst.m_arg == 0xDEADBEEF) // break, jump to end 288 | inst.m_arg = endBlocks; 289 | } 290 | return; 291 | } 292 | 293 | void Compiler::visit (const ASTBreak& break_stmt, std::shared_ptr func) 294 | { 295 | func->code()->write(OP_BR, 0xDEADBEEF); 296 | } 297 | 298 | void Compiler::visit (const ASTContinue& cont_stmt, std::shared_ptr func) 299 | { 300 | func->code()->write(OP_BR, 0xFEEDBEAD); 301 | } 302 | 303 | void Compiler::visit (const ASTReturn& ret_stmt, std::shared_ptr func) 304 | { 305 | ret_stmt.ret()->accept (*this, func); 306 | func->code()->write (OP_RETURN); 307 | } 308 | 309 | void Compiler::visit (const ASTStmtExpr& expr_stmt, std::shared_ptr func) 310 | { 311 | expr_stmt.expr()->accept (*this, func); 312 | func->code ()->write (OP_POP); 313 | } 314 | 315 | void Compiler::visit (const ASTExpression& expr, std::shared_ptr func) 316 | { 317 | const std::vector>& exprs = expr.exprs (); 318 | 319 | for (uint32_t i = 0; i < exprs.size (); i++) { 320 | exprs[i]->accept(*this, func); 321 | } 322 | } 323 | 324 | void Compiler::visit (const ASTAssignment& expr, std::shared_ptr func) 325 | { 326 | if (func->scope()->find(expr.var()).get () == nullptr) { 327 | func->scope()->define(expr.var(), std::shared_ptr(new Nil ())); 328 | } 329 | 330 | expr.expr()->accept (*this, func); 331 | func->code ()->write (OP_SET, std::shared_ptr(new String (expr.var()))); 332 | } 333 | 334 | 335 | void Compiler::visit (const ASTCompare& expr, std::shared_ptr func) 336 | { 337 | expr.left ()->accept (*this, func); 338 | expr.right ()->accept (*this, func); 339 | 340 | std::shared_ptr code = func->code (); 341 | 342 | switch (expr.op_type ()) 343 | { 344 | case ASTCompare::OR: code->write (OP_OR); break; 345 | case ASTCompare::AND: code->write (OP_AND); break; 346 | case ASTCompare::EQUALS_EQUALS: code->write (OP_EQEQ); break; 347 | case ASTCompare::NOT_EQUALS: code->write (OP_NEQ); break; 348 | case ASTCompare::LESS_THAN: code->write (OP_LT); break; 349 | case ASTCompare::GREATER_THAN: code->write (OP_GT); break; 350 | case ASTCompare::LESS_THAN_EQUALS: code->write (OP_LTE); break; 351 | case ASTCompare::GREATER_THAN_EQUALS: code->write (OP_GTE); break; 352 | } 353 | } 354 | 355 | void Compiler::visit (const ASTBinaryMathOp& expr, std::shared_ptr func) 356 | { 357 | expr.left ()->accept (*this, func); 358 | expr.right ()->accept (*this, func); 359 | 360 | std::shared_ptr code = func->code (); 361 | 362 | switch (expr.op_type ()) 363 | { 364 | case ASTBinaryMathOp::PLUS: code->write (OP_ADD); break; 365 | case ASTBinaryMathOp::MINUS: code->write (OP_SUB); break; 366 | case ASTBinaryMathOp::TIMES: code->write (OP_MUL); break; 367 | case ASTBinaryMathOp::DIVIDE: code->write (OP_DIV); break; 368 | } 369 | } 370 | 371 | void Compiler::visit (const ASTUnaryMathOp& expr, std::shared_ptr func) 372 | { 373 | expr.expr ()->accept (*this, func); 374 | 375 | std::shared_ptr code = func->code (); 376 | 377 | switch (expr.op_type ()) 378 | { 379 | case ASTUnaryMathOp::MINUS: code->write (OP_NEG); break; 380 | case ASTUnaryMathOp::NOT: code->write (OP_NOT); break; 381 | case ASTUnaryMathOp::INCREMENT: code->write (OP_INC); break; 382 | case ASTUnaryMathOp::DECREMENT: code->write (OP_DEC); break; 383 | } 384 | } 385 | 386 | void Compiler::visit (const ASTNew& expr, std::shared_ptr func) 387 | { 388 | const std::string& name = expr.name(); 389 | const std::vector>& args = expr.args (); 390 | 391 | std::shared_ptr _class = m_env.find_class (name); 392 | 393 | if (_class.get () == nullptr) { 394 | ThrowCompileError("Compiler : Class '%s' does not exist.", name.c_str ()); 395 | } 396 | 397 | std::shared_ptr constructor = _class->find_func(name); 398 | 399 | if (constructor.get () == nullptr) { 400 | ThrowCompileError("Compiler : Constructor for class '%s' does not exist.", name.c_str ()); 401 | } 402 | 403 | if (args.size () != constructor->args ().size ()) { 404 | ThrowCompileError("Compiler : Function '%s' expects %i arguments.", expr.name().c_str(), constructor->args().size ()); 405 | } 406 | 407 | for (uint32_t i = 0; i < args.size (); i++) { 408 | args[i]->accept (*this, func); 409 | } 410 | 411 | auto instance = std::shared_ptr(new Instance (_class)); 412 | 413 | func->code ()->write (OP_PUSH, instance); 414 | func->code ()->write (OP_PUSH, std::shared_ptr (new Number (args.size ()))); 415 | func->code ()->write (OP_MCALL, std::shared_ptr (new String (expr.name()))); 416 | func->code ()->write (OP_PUSH, instance); 417 | } 418 | 419 | void Compiler::visit (const ASTGFuncCall& expr, std::shared_ptr func) 420 | { 421 | std::shared_ptr code = func->code (); 422 | const std::vector>& args = expr.args (); 423 | 424 | exportedFunction efunc = m_env.findExportedFunction(expr.name()); 425 | if (efunc != nullptr) 426 | { 427 | if (args.size () != 1) { 428 | ThrowCompileError("Compiler : Call to print has more than one argument."); 429 | } 430 | 431 | for (uint32_t i = 0; i < args.size(); i++) 432 | args[i]->accept(*this, func); 433 | 434 | func->code()->write (OP_PUSH, std::shared_ptr(new Number(args.size()))); 435 | code->write (OP_ECALL, std::shared_ptr(new String (expr.name().c_str()))); 436 | } 437 | else 438 | { 439 | std::shared_ptr call_func = m_env.find_func(expr.name().c_str()); 440 | 441 | if (call_func == nullptr) 442 | ThrowCompileError("Compiler : Function '%s' has not been defined.", expr.name().c_str()); 443 | 444 | if (args.size () != call_func->args ().size()) 445 | ThrowCompileError("Compiler : Function '%s' expects %i arguments.", expr.name().c_str(), call_func->args().size()); 446 | 447 | for (uint32_t i = 0; i < args.size (); i++) 448 | args[i]->accept(*this, func); 449 | 450 | code->write(OP_CALL, std::shared_ptr(new String (expr.name().c_str()))); 451 | } 452 | } 453 | 454 | void Compiler::visit (const ASTMFuncCall& expr, std::shared_ptr func) 455 | { 456 | const std::string& name = expr.name(); 457 | const std::string& base = expr.base(); 458 | const std::vector>& args = expr.args (); 459 | 460 | for (uint32_t i = 0; i < args.size (); i++) 461 | args[i]->accept (*this, func); 462 | 463 | func->code ()->write (OP_REF, std::shared_ptr (new String(base))); 464 | func->code ()->write (OP_PUSH, std::shared_ptr (new Number(args.size()))); 465 | func->code ()->write (OP_MCALL, std::shared_ptr (new String (expr.name()))); 466 | } 467 | 468 | void Compiler::visit (const ASTIdentifier& expr, std::shared_ptr func) 469 | { 470 | std::shared_ptr var = func->scope ()->find (expr.name()); 471 | 472 | if (var.get () == nullptr) 473 | { 474 | func->scope ()->define (expr.name(), std::shared_ptr (new Nil ())); 475 | var = func->scope ()->find (expr.name()); 476 | } 477 | 478 | func->code ()->write (OP_REF, std::shared_ptr (new String (expr.name()))); 479 | } 480 | 481 | void Compiler::visit (const ASTNumber& num, std::shared_ptr func) 482 | { 483 | func->code ()->write (OP_PUSH, std::shared_ptr (new Number (num.value ()))); 484 | } 485 | 486 | void Compiler::visit (const ASTString& str, std::shared_ptr func) 487 | { 488 | func->code ()->write (OP_PUSH, std::shared_ptr (new String (str.text ()))); 489 | } 490 | 491 | void Compiler::visit (const ASTNil& nil, std::shared_ptr func) 492 | { 493 | func->code ()->write (OP_PUSH, m_env.obj_nil ()); 494 | } 495 | 496 | void Compiler::visit (const ASTTrue& expr, std::shared_ptr func) 497 | { 498 | func->code ()->write (OP_PUSH, m_env.obj_true ()); 499 | } 500 | 501 | void Compiler::visit (const ASTFalse& expr, std::shared_ptr func) 502 | { 503 | func->code ()->write (OP_PUSH, m_env.obj_false ()); 504 | } 505 | } -------------------------------------------------------------------------------- /signal/Compiler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Enviroment.h" 4 | #include "Error.h" 5 | #include "Parser.h" 6 | #include "Scope.h" 7 | #include "VisitorInterface.h" 8 | 9 | namespace Signal 10 | { 11 | class Compiler : private VisitorInterface 12 | { 13 | public: 14 | 15 | static void Compile (Environment& env, std::shared_ptr ast); 16 | 17 | private: 18 | 19 | Compiler (Environment& env); 20 | 21 | virtual void visit (const AST& ast); 22 | virtual void visit (const ASTClassDef& class_def); 23 | virtual void visit (const ASTMFuncDecl& func_decl); 24 | virtual void visit (const ASTGFuncDecl& func_decl); 25 | virtual void visit (const ASTVarDef& var_def, std::shared_ptr _class); 26 | virtual void visit (const ASTFuncDef& func_def, std::shared_ptr _class); 27 | virtual void visit (const ASTBlock& block, std::shared_ptr func); 28 | virtual void visit (const ASTIf& if_stmt, std::shared_ptr func); 29 | virtual void visit (const ASTWhile& while_stmt, std::shared_ptr func); 30 | virtual void visit (const ASTFor& for_stmt, std::shared_ptr func); 31 | virtual void visit (const ASTSwitch& switch_stmt, std::shared_ptr func); 32 | virtual void visit (const ASTBreak& break_stmt, std::shared_ptr func); 33 | virtual void visit (const ASTContinue& cont_stmt, std::shared_ptr func); 34 | virtual void visit (const ASTReturn& ret_stmt, std::shared_ptr func); 35 | virtual void visit (const ASTStmtExpr& expr_stmt, std::shared_ptr func); 36 | virtual void visit (const ASTExpression& expr, std::shared_ptr func); 37 | virtual void visit (const ASTAssignment& expr, std::shared_ptr func); 38 | virtual void visit (const ASTCompare& expr, std::shared_ptr func); 39 | virtual void visit (const ASTBinaryMathOp& expr, std::shared_ptr func); 40 | virtual void visit (const ASTUnaryMathOp& expr, std::shared_ptr func); 41 | virtual void visit (const ASTNew& expr, std::shared_ptr func); 42 | virtual void visit (const ASTGFuncCall& expr, std::shared_ptr func); 43 | virtual void visit (const ASTMFuncCall& expr, std::shared_ptr func); 44 | virtual void visit (const ASTIdentifier& expr, std::shared_ptr func); 45 | virtual void visit (const ASTNumber& num, std::shared_ptr func); 46 | virtual void visit (const ASTString& str, std::shared_ptr func); 47 | virtual void visit (const ASTNil& nil, std::shared_ptr func); 48 | virtual void visit (const ASTTrue& expr, std::shared_ptr func); 49 | virtual void visit (const ASTFalse& expr, std::shared_ptr func); 50 | 51 | Environment& m_env; 52 | }; 53 | } -------------------------------------------------------------------------------- /signal/Enviroment.cpp: -------------------------------------------------------------------------------- 1 | #include "Enviroment.h" 2 | 3 | namespace Signal 4 | { 5 | Environment::Environment () 6 | { 7 | m_obj_nil = std::shared_ptr (new Nil ()); 8 | m_obj_true = std::shared_ptr (new True ()); 9 | m_obj_false = std::shared_ptr (new False ()); 10 | } 11 | 12 | void Environment::add_class (std::shared_ptr _class) 13 | { 14 | m_classes.push_back(_class); 15 | } 16 | 17 | void Environment::add_func (std::shared_ptr func) 18 | { 19 | m_funcs.push_back(func); 20 | } 21 | 22 | void Environment::exportFunction(const std::string& name, exportedFunction func) 23 | { 24 | m_exportedFuncs.insert(std::make_pair(name, func)); 25 | } 26 | 27 | std::shared_ptr Environment::find_class (const std::string& name) 28 | { 29 | std::shared_ptr ret; 30 | 31 | for (uint32_t i = 0; i < m_classes.size (); i++) { 32 | if (name == m_classes[i]->name ()) { 33 | ret = m_classes[i]; 34 | } 35 | } 36 | 37 | return ret; 38 | } 39 | 40 | std::shared_ptr Environment::find_func(const std::string& name) 41 | { 42 | std::shared_ptr ret; 43 | 44 | for (uint32_t i = 0; i < m_funcs.size (); i++) { 45 | if (name == m_funcs[i]->name ()) { 46 | ret = m_funcs[i]; 47 | } 48 | } 49 | 50 | return ret; 51 | } 52 | 53 | exportedFunction Environment::findExportedFunction(const std::string& name) 54 | { 55 | if (m_exportedFuncs[name]) 56 | return m_exportedFuncs[name]; 57 | return nullptr; 58 | } 59 | 60 | std::shared_ptr Environment::obj_nil () 61 | { 62 | return m_obj_nil; 63 | } 64 | 65 | std::shared_ptr Environment::obj_true () 66 | { 67 | return m_obj_true; 68 | } 69 | 70 | std::shared_ptr Environment::obj_false () 71 | { 72 | return m_obj_false; 73 | } 74 | } -------------------------------------------------------------------------------- /signal/Enviroment.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "Code.h" 5 | #include "Scope.h" 6 | 7 | namespace Signal 8 | { 9 | class Environment; 10 | 11 | typedef std::shared_ptr (*exportedFunction)(Environment env, std::vector> args); 12 | class Environment 13 | { 14 | public: 15 | 16 | Environment (); 17 | 18 | void add_class (std::shared_ptr _class); 19 | void add_func(std::shared_ptr func); 20 | 21 | void exportFunction(const std::string& name, exportedFunction func); 22 | 23 | std::shared_ptr find_class (const std::string& name); 24 | std::shared_ptr find_func (const std::string& name); 25 | exportedFunction findExportedFunction(const std::string& name); 26 | 27 | std::shared_ptr obj_nil (); 28 | std::shared_ptr obj_true (); 29 | std::shared_ptr obj_false (); 30 | 31 | private: 32 | 33 | std::vector> m_classes; 34 | std::vector> m_funcs; 35 | std::map m_exportedFuncs; 36 | 37 | // Built-in primitive objects 38 | std::shared_ptr m_obj_nil; 39 | std::shared_ptr m_obj_true; 40 | std::shared_ptr m_obj_false; 41 | }; 42 | } -------------------------------------------------------------------------------- /signal/Error.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Error.h" 4 | 5 | namespace Signal 6 | { 7 | Error::Error (std::string error, ...) : m_positionInfo(false), m_internalInfo(false) 8 | { 9 | va_list args; 10 | va_start (args, error); 11 | this->makeString(error, args); 12 | va_end (args); 13 | } 14 | 15 | Error::Error (uint32_t line, uint32_t character, std::string error, ...) 16 | : m_positionInfo(true), m_internalInfo(false), m_line(line), m_character(character) 17 | { 18 | va_list args; 19 | va_start (args, error); 20 | this->makeString(error, args); 21 | va_end (args); 22 | } 23 | 24 | Error::Error(uint32_t internalLine, const char* internalFile, std::string error, ...) 25 | : m_positionInfo(false), m_internalInfo(true), m_internalLine(internalLine), m_internalFile(internalFile) 26 | { 27 | va_list args; 28 | va_start (args, error); 29 | this->makeString(error, args); 30 | va_end (args); 31 | } 32 | 33 | Error::Error (uint32_t internalLine, const char* internalFile, uint32_t line, uint32_t character, std::string error, ...) 34 | : m_positionInfo(true), m_internalInfo(true), m_internalLine(internalLine), m_internalFile(internalFile), m_line(line), m_character(character) 35 | { 36 | va_list args; 37 | va_start (args, error); 38 | this->makeString(error, args); 39 | va_end (args); 40 | } 41 | 42 | void Error::makeString(std::string error, va_list args) 43 | { 44 | char temp_buffer[ERROR_MAX_LENGTH]; 45 | vsprintf_s (temp_buffer, error.c_str (), args); 46 | this->m_error = std::string(temp_buffer); 47 | } 48 | 49 | 50 | std::string Error::getError() 51 | { 52 | return this->m_error; 53 | } 54 | 55 | bool Error::hasPositionInfo() 56 | { 57 | return this->m_positionInfo; 58 | } 59 | uint32_t Error::getLine() 60 | { 61 | return this->m_line; 62 | } 63 | uint32_t Error::getCharacter() 64 | { 65 | return this->m_character; 66 | } 67 | 68 | bool Error::hasInternalInfo() 69 | { 70 | return this->m_internalInfo; 71 | } 72 | uint32_t Error::getInternalLine() 73 | { 74 | return this->m_internalLine; 75 | } 76 | const char* Error::getInternalFile() 77 | { 78 | return this->m_internalFile; 79 | } 80 | } -------------------------------------------------------------------------------- /signal/Error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Types.h" 6 | 7 | #define ThrowSignalError(a, c, format, ...) throw Error(__LINE__, __FILE__, a, c, format, __VA_ARGS__); 8 | #define ThrowCompileError(format, ...) throw Error(__LINE__, __FILE__, format, __VA_ARGS__); 9 | 10 | namespace Signal 11 | { 12 | #define ERROR_MAX_LENGTH 2048 13 | 14 | class Error 15 | { 16 | public: 17 | 18 | Error(std::string error, ...); 19 | Error(uint32_t line, uint32_t character, std::string error, ...); 20 | Error(uint32_t internalLine, const char* internalFile, std::string error, ...); 21 | Error(uint32_t internalLine, const char* internalFile, uint32_t line, uint32_t character, std::string error, ...); 22 | 23 | std::string getError(); 24 | bool hasPositionInfo(); 25 | uint32_t getLine(); 26 | uint32_t getCharacter(); 27 | bool hasInternalInfo(); 28 | uint32_t getInternalLine(); 29 | const char* getInternalFile(); 30 | 31 | private: 32 | void makeString(std::string error, va_list args); 33 | 34 | bool m_positionInfo, m_internalInfo; 35 | std::string m_error; 36 | uint32_t m_line; 37 | uint32_t m_character; 38 | uint32_t m_internalLine; 39 | const char* m_internalFile; 40 | }; 41 | } -------------------------------------------------------------------------------- /signal/FileInput.cpp: -------------------------------------------------------------------------------- 1 | #include "FileInput.h" 2 | 3 | namespace Signal 4 | { 5 | FileInput::FileInput (const std::string& file) 6 | { 7 | std::ifstream stream (file, std::ifstream::in | std::ifstream::binary); 8 | 9 | if (!stream.is_open ()) { 10 | throw Error ("FileInput : Unable to open source file for input."); 11 | } 12 | 13 | m_buffer.swap (std::vector ((std::istreambuf_iterator (stream)), std::istreambuf_iterator ())); 14 | stream.close (); 15 | 16 | // Hack : the lexer checks for the end of the file but there are already two buffered characters 17 | m_buffer.push_back (' '); 18 | m_buffer.push_back (' '); 19 | 20 | m_it = m_buffer.begin (); 21 | } 22 | 23 | bool FileInput::is_eof () const 24 | { 25 | return (m_it == m_buffer.end ()); 26 | } 27 | 28 | int8_t FileInput::read () 29 | { 30 | return *m_it++; 31 | } 32 | } -------------------------------------------------------------------------------- /signal/FileInput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Error.h" 9 | #include "Types.h" 10 | 11 | namespace Signal 12 | { 13 | class FileInput 14 | { 15 | public: 16 | 17 | FileInput (const std::string& file); 18 | 19 | bool is_eof () const; 20 | 21 | int8_t read (); 22 | 23 | private: 24 | 25 | std::vector m_buffer; 26 | std::vector::iterator m_it; 27 | }; 28 | } -------------------------------------------------------------------------------- /signal/Interpreter.cpp: -------------------------------------------------------------------------------- 1 | #include "Interpreter.h" 2 | 3 | namespace Signal 4 | { 5 | Interpreter::Interpreter (Environment& env) 6 | : 7 | m_env (env) 8 | {} 9 | 10 | void Interpreter::execute () 11 | { 12 | std::shared_ptr func = m_env.find_func ("main"); 13 | 14 | if (func.get () == nullptr) { 15 | throw Error ("Interpreter : main () does not exist."); 16 | } 17 | 18 | m_frames.push (CallFrame (func)); 19 | m_scopes.push (func->scope ()); 20 | 21 | while (m_frames.size () > 0) { 22 | CallFrame& frame = m_frames.top (); 23 | Instruction& instruction = (*frame.m_func->code ())[frame.m_address]; 24 | 25 | frame.m_address++; 26 | 27 | switch (instruction.m_op) 28 | { 29 | case OP_PUSH: m_stack.push (instruction.m_object); break; 30 | case OP_POP: m_stack.pop (); break; 31 | case OP_NIL: m_stack.push (m_env.obj_nil()); break; 32 | 33 | case OP_CALL: 34 | { 35 | std::shared_ptr call_func = m_env.find_func(instruction.m_object->getString()->text()); 36 | 37 | if (call_func.get () == nullptr) { 38 | throw Error ("Interpreter : function '%s' does not exist.", instruction.m_object->getString()->text()); 39 | } 40 | 41 | m_frames.push (CallFrame(call_func)); 42 | call_func->scope ()->reset (); 43 | m_scopes.push (std::shared_ptr (new Scope (*call_func->scope ()))); 44 | } 45 | break; 46 | 47 | case OP_MCALL: 48 | { 49 | double_t num_args = m_stack.top()->getNumber()->number(); 50 | m_stack.pop (); 51 | 52 | std::shared_ptr instance = m_stack.top(); 53 | //m_stack.pop(); 54 | 55 | Object::Type t = instance.get()->type(); 56 | if (instance.get()->type() != Object::INSTANCE) 57 | throw Error ("Interpreter : Member call expected class instance."); 58 | 59 | std::shared_ptr _class = dynamic_cast(instance.get())->_class(); 60 | std::shared_ptr call_func = _class->find_func(instruction.m_object->getString()->text()); 61 | if (call_func.get () == nullptr) { 62 | throw Error ("Interpreter : Class '%s' does not define the function '%s'.", _class.get()->name().c_str(), call_func.get()->name().c_str()); 63 | } 64 | 65 | m_frames.push (CallFrame(call_func)); 66 | call_func->scope()->reset(); 67 | call_func->scope()->setParent(_class.get()->scope()); 68 | m_scopes.push(call_func->scope()); 69 | } 70 | break; 71 | 72 | case OP_RETURN: 73 | { 74 | m_frames.pop(); 75 | m_scopes.pop(); 76 | } 77 | break; 78 | 79 | case OP_ECALL: 80 | { 81 | int32_t argCount = m_stack.top()->getNumber()->number(); 82 | m_stack.pop(); 83 | 84 | std::vector> args; 85 | for (int i = 0; i < argCount; i++) 86 | { 87 | args.push_back(m_stack.top()); 88 | m_stack.pop(); 89 | } 90 | 91 | exportedFunction efunc = m_env.findExportedFunction(instruction.m_object->getString()->text()); 92 | 93 | if (efunc == nullptr) 94 | throw Error ("Interpreter : exported function '%s' does not exist.", instruction.m_object->getString()->text()); 95 | 96 | std::shared_ptr returnValue = efunc(m_env, args); 97 | if (returnValue != nullptr) 98 | m_stack.push(returnValue); 99 | else 100 | m_stack.push(m_env.obj_nil()); 101 | } 102 | break; 103 | 104 | case OP_SET: 105 | { 106 | const std::string& name = instruction.m_object->getString()->text(); 107 | m_scopes.top()->set(name, m_stack.top()); 108 | } 109 | break; 110 | 111 | case OP_DEF: 112 | { 113 | const std::string& name = instruction.m_object->getString()->text(); 114 | m_scopes.top()->define(name, m_stack.top()); 115 | } 116 | break; 117 | 118 | case OP_REF: 119 | { 120 | const std::string& name = instruction.m_object->getString()->text(); 121 | std::shared_ptr arg = m_scopes.top()->find(name); 122 | m_stack.push (arg); 123 | } 124 | break; 125 | 126 | case OP_BR: 127 | { 128 | frame.m_address = instruction.m_arg; 129 | } 130 | break; 131 | 132 | case OP_BRT: 133 | { 134 | if (m_stack.top ()->type () == Object::TRUE) { 135 | frame.m_address = instruction.m_arg; 136 | } 137 | m_stack.pop (); 138 | } 139 | break; 140 | 141 | case OP_BRF: 142 | { 143 | if (m_stack.top ()->type () == Object::FALSE) { 144 | frame.m_address = instruction.m_arg; 145 | } 146 | m_stack.pop (); 147 | } 148 | break; 149 | 150 | case OP_ADD: 151 | { 152 | std::shared_ptr right = m_stack.top (); 153 | m_stack.pop (); 154 | 155 | std::shared_ptr left = m_stack.top (); 156 | m_stack.pop (); 157 | 158 | switch (left->type ()) 159 | { 160 | case Object::NUMBER: 161 | { 162 | switch (right->type ()) 163 | { 164 | case Object::NUMBER: 165 | { 166 | m_stack.push (std::shared_ptr (new Number (dynamic_cast (left.get ())->number () + dynamic_cast (right.get ())->number ()))); 167 | } 168 | break; 169 | 170 | default: 171 | { 172 | throw Error ("Interpreter : Type mismatch on operator '+'."); 173 | } 174 | break; 175 | } 176 | } 177 | break; 178 | 179 | case Object::STRING: 180 | { 181 | switch (right->type ()) 182 | { 183 | case Object::STRING: 184 | { 185 | m_stack.push (std::shared_ptr (new String (dynamic_cast (left.get ())->text () + dynamic_cast (right.get ())->text ()))); 186 | } 187 | break; 188 | 189 | default: 190 | { 191 | throw Error ("Interpreter : Type mismatch on operator '+'."); 192 | } 193 | break; 194 | } 195 | } 196 | break; 197 | 198 | default: 199 | { 200 | throw Error ("Interpreter : Invalid arguments to operator '+'."); 201 | } 202 | break; 203 | } 204 | } 205 | break; 206 | 207 | case OP_SUB: 208 | { 209 | std::shared_ptr right = m_stack.top (); 210 | m_stack.pop (); 211 | 212 | std::shared_ptr left = m_stack.top (); 213 | m_stack.pop (); 214 | 215 | switch (left->type ()) 216 | { 217 | case Object::NUMBER: 218 | { 219 | switch (right->type ()) 220 | { 221 | case Object::NUMBER: 222 | { 223 | m_stack.push (std::shared_ptr (new Number (dynamic_cast (left.get ())->number () - dynamic_cast (right.get ())->number ()))); 224 | } 225 | break; 226 | 227 | default: 228 | { 229 | throw Error ("Interpreter : Type mismatch on operator '-'."); 230 | } 231 | break; 232 | } 233 | } 234 | break; 235 | 236 | default: 237 | { 238 | throw Error ("Interpreter : Invalid arguments to operator '-'."); 239 | } 240 | break; 241 | } 242 | } 243 | break; 244 | 245 | case OP_MUL: 246 | { 247 | std::shared_ptr right = m_stack.top (); 248 | m_stack.pop (); 249 | 250 | std::shared_ptr left = m_stack.top ();; 251 | m_stack.pop (); 252 | 253 | switch (left->type ()) 254 | { 255 | case Object::NUMBER: 256 | { 257 | switch (right->type ()) 258 | { 259 | case Object::NUMBER: 260 | { 261 | m_stack.push (std::shared_ptr (new Number (dynamic_cast (left.get ())->number () * dynamic_cast (right.get ())->number ()))); 262 | } 263 | break; 264 | 265 | default: 266 | { 267 | throw Error ("Interpreter : Type mismatch on operator '*'."); 268 | } 269 | break; 270 | } 271 | } 272 | break; 273 | 274 | default: 275 | { 276 | throw Error ("Interpreter : Invalid arguments to operator '*'."); 277 | } 278 | break; 279 | } 280 | } 281 | break; 282 | 283 | case OP_DIV: 284 | { 285 | std::shared_ptr right = m_stack.top (); 286 | m_stack.pop (); 287 | 288 | std::shared_ptr left = m_stack.top ();; 289 | m_stack.pop (); 290 | 291 | switch (left->type ()) 292 | { 293 | case Object::NUMBER: 294 | { 295 | switch (right->type ()) 296 | { 297 | case Object::NUMBER: 298 | { 299 | if (dynamic_cast (right.get ())->number () == 0) { 300 | m_stack.push (std::shared_ptr (new Nil ())); 301 | } else { 302 | m_stack.push (std::shared_ptr (new Number (dynamic_cast (left.get ())->number () / dynamic_cast (right.get ())->number ()))); 303 | } 304 | } 305 | break; 306 | 307 | default: 308 | { 309 | throw Error ("Interpreter : Type mismatch on operator '/'."); 310 | } 311 | break; 312 | } 313 | } 314 | break; 315 | 316 | default: 317 | { 318 | throw Error ("Interpreter : Invalid arguments to operator '/'."); 319 | } 320 | break; 321 | } 322 | } 323 | break; 324 | 325 | case OP_NEG: 326 | { 327 | std::shared_ptr value = m_stack.top (); 328 | m_stack.pop (); 329 | 330 | switch (value->type()) 331 | { 332 | case Object::NUMBER: 333 | { 334 | m_stack.push (std::shared_ptr (new Number (-dynamic_cast (value.get ())->number ()))); 335 | } 336 | break; 337 | 338 | default: 339 | { 340 | throw Error ("Interpreter : Invalid arguments to operator '-'."); 341 | } 342 | break; 343 | } 344 | } 345 | break; 346 | 347 | case OP_INC: 348 | { 349 | std::shared_ptr identifier = m_stack.top (); 350 | switch (identifier->type()) 351 | { 352 | case Object::NUMBER: 353 | { 354 | Number* num = dynamic_cast(identifier.get()); 355 | num->set(num->number() + 1); 356 | } 357 | break; 358 | case Object::NIL: 359 | throw Error ("Interpreter : Attempt to increment an uninitialized variable."); 360 | break; 361 | default: 362 | throw Error ("Interpreter : Attempt to increment invalid value."); 363 | break; 364 | } 365 | } 366 | break; 367 | case OP_DEC: 368 | { 369 | std::shared_ptr identifier = m_stack.top (); 370 | switch (identifier->type()) 371 | { 372 | case Object::NUMBER: 373 | { 374 | Number* num = dynamic_cast(identifier.get()); 375 | num->set(num->number() - 1); 376 | } 377 | break; 378 | case Object::NIL: 379 | throw Error ("Interpreter : Attempt to decrement an uninitialized variable.."); 380 | break; 381 | default: 382 | throw Error ("Interpreter : Attempt to decrement invalid value."); 383 | break; 384 | } 385 | } 386 | break; 387 | 388 | case OP_NOT: 389 | { 390 | std::shared_ptr value = m_stack.top (); 391 | m_stack.pop (); 392 | 393 | switch (value->type ()) 394 | { 395 | case Object::TRUE: 396 | { 397 | m_stack.push (std::shared_ptr (new False ())); 398 | } 399 | break; 400 | 401 | case Object::FALSE: 402 | { 403 | m_stack.push (std::shared_ptr (new True ())); 404 | } 405 | break; 406 | 407 | default: 408 | { 409 | throw Error ("Interpreter : Invalid arguments to operator '!'."); 410 | } 411 | break; 412 | } 413 | } 414 | break; 415 | 416 | case OP_OR: 417 | { 418 | std::shared_ptr right = m_stack.top (); 419 | m_stack.pop (); 420 | 421 | std::shared_ptr left = m_stack.top ();; 422 | m_stack.pop (); 423 | 424 | switch (left->type ()) 425 | { 426 | case Object::TRUE: 427 | { 428 | switch (right->type ()) 429 | { 430 | case Object::TRUE: 431 | { 432 | m_stack.push (std::shared_ptr (new True ())); 433 | } 434 | break; 435 | 436 | case Object::FALSE: 437 | { 438 | m_stack.push (std::shared_ptr (new True ())); 439 | } 440 | break; 441 | 442 | default: 443 | { 444 | throw Error ("Interpreter : Type mismatch on operator '||'."); 445 | } 446 | break; 447 | } 448 | } 449 | break; 450 | 451 | case Object::FALSE: 452 | { 453 | switch (right->type ()) 454 | { 455 | case Object::TRUE: 456 | { 457 | m_stack.push (std::shared_ptr (new True ())); 458 | } 459 | break; 460 | 461 | case Object::FALSE: 462 | { 463 | m_stack.push (std::shared_ptr (new False ())); 464 | } 465 | break; 466 | 467 | default: 468 | { 469 | throw Error ("Interpreter : Type mismatch on operator '||'."); 470 | } 471 | break; 472 | } 473 | } 474 | break; 475 | 476 | default: 477 | { 478 | throw Error ("Interpreter : Invalid arguments to operator '||'."); 479 | } 480 | break; 481 | } 482 | } 483 | break; 484 | 485 | case OP_AND: 486 | { 487 | std::shared_ptr right = m_stack.top (); 488 | m_stack.pop (); 489 | 490 | std::shared_ptr left = m_stack.top ();; 491 | m_stack.pop (); 492 | 493 | switch (left->type ()) 494 | { 495 | case Object::TRUE: 496 | { 497 | switch (right->type ()) 498 | { 499 | case Object::TRUE: 500 | { 501 | m_stack.push (std::shared_ptr (new True ())); 502 | } 503 | break; 504 | 505 | case Object::FALSE: 506 | { 507 | m_stack.push (std::shared_ptr (new False ())); 508 | } 509 | break; 510 | 511 | default: 512 | { 513 | throw Error ("Interpreter : Type mismatch on operator '||'."); 514 | } 515 | break; 516 | } 517 | } 518 | break; 519 | 520 | case Object::FALSE: 521 | { 522 | switch (right->type ()) 523 | { 524 | case Object::TRUE: 525 | { 526 | m_stack.push (std::shared_ptr (new False ())); 527 | } 528 | break; 529 | 530 | case Object::FALSE: 531 | { 532 | m_stack.push (std::shared_ptr (new False ())); 533 | } 534 | break; 535 | 536 | default: 537 | { 538 | throw Error ("Interpreter : Type mismatch on operator '||'."); 539 | } 540 | break; 541 | } 542 | } 543 | break; 544 | 545 | default: 546 | { 547 | throw Error ("Interpreter : Invalid arguments to operator '||'."); 548 | } 549 | break; 550 | } 551 | } 552 | break; 553 | 554 | case OP_EQEQ: 555 | { 556 | std::shared_ptr right = m_stack.top(); 557 | m_stack.pop(); 558 | 559 | std::shared_ptr left = m_stack.top(); 560 | m_stack.pop(); 561 | 562 | if (*left.get() == *right.get()) 563 | m_stack.push(std::shared_ptr(new True())); 564 | else 565 | m_stack.push(std::shared_ptr(new False())); 566 | } 567 | break; 568 | 569 | case OP_NEQ: 570 | { 571 | std::shared_ptr right = m_stack.top (); 572 | m_stack.pop (); 573 | 574 | std::shared_ptr left = m_stack.top ();; 575 | m_stack.pop (); 576 | 577 | if (*left.get() != *right.get()) 578 | m_stack.push(std::shared_ptr (new True())); 579 | else 580 | m_stack.push(std::shared_ptr (new False())); 581 | } 582 | break; 583 | 584 | case OP_LT: 585 | { 586 | std::shared_ptr right = m_stack.top (); 587 | m_stack.pop (); 588 | 589 | std::shared_ptr left = m_stack.top ();; 590 | m_stack.pop (); 591 | 592 | if (*left.get() < *right.get()) 593 | m_stack.push(std::shared_ptr (new True())); 594 | else 595 | m_stack.push(std::shared_ptr (new False())); 596 | } 597 | break; 598 | 599 | case OP_GT: 600 | { 601 | std::shared_ptr right = m_stack.top(); 602 | m_stack.pop(); 603 | 604 | std::shared_ptr left = m_stack.top(); 605 | m_stack.pop(); 606 | 607 | if (*left.get() > *right.get()) 608 | m_stack.push(std::shared_ptr (new True())); 609 | else 610 | m_stack.push(std::shared_ptr (new False())); 611 | } 612 | break; 613 | 614 | case OP_LTE: 615 | { 616 | std::shared_ptr right = m_stack.top(); 617 | m_stack.pop(); 618 | 619 | std::shared_ptr left = m_stack.top(); 620 | m_stack.pop(); 621 | 622 | if (*left.get() <= *right.get()) 623 | m_stack.push(std::shared_ptr (new True())); 624 | else 625 | m_stack.push(std::shared_ptr (new False())); 626 | } 627 | break; 628 | 629 | case OP_GTE: 630 | { 631 | std::shared_ptr right = m_stack.top(); 632 | m_stack.pop(); 633 | 634 | std::shared_ptr left = m_stack.top(); 635 | m_stack.pop(); 636 | 637 | if (*left.get() >= *right.get()) 638 | m_stack.push(std::shared_ptr (new True())); 639 | else 640 | m_stack.push(std::shared_ptr (new False())); 641 | } 642 | break; 643 | } 644 | } 645 | } 646 | } -------------------------------------------------------------------------------- /signal/Interpreter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Enviroment.h" 7 | 8 | namespace Signal 9 | { 10 | class Interpreter 11 | { 12 | public: 13 | 14 | Interpreter (Environment& env); 15 | 16 | void execute (); 17 | 18 | private: 19 | 20 | struct CallFrame 21 | { 22 | CallFrame (std::shared_ptr func) 23 | : 24 | m_address (0), 25 | m_func (func) 26 | {} 27 | 28 | CallFrame (std::shared_ptr func, std::shared_ptr instance) 29 | : 30 | m_address (0), 31 | m_func (func), 32 | m_instance (instance) 33 | {} 34 | 35 | uint32_t m_address; 36 | 37 | std::shared_ptr m_instance; 38 | std::shared_ptr m_func; 39 | }; 40 | 41 | Environment& m_env; 42 | 43 | std::stack m_frames; 44 | std::stack> m_stack; 45 | std::stack> m_scopes; 46 | }; 47 | } -------------------------------------------------------------------------------- /signal/Lexer.cpp: -------------------------------------------------------------------------------- 1 | #include "Lexer.h" 2 | #include "Utils.h" 3 | 4 | 5 | namespace Signal 6 | { 7 | Lexer::Lexer (FileInput& file) 8 | : 9 | m_file (file), 10 | m_line (1) 11 | { 12 | // Fill up our buffers and reset the character offset 13 | consume (); 14 | consume (); 15 | m_character = 0; 16 | 17 | // Add keywords 18 | m_keywords.insert (std::pair("function", Token::FUNC)); 19 | m_keywords.insert (std::pair("class", Token::CLASS)); 20 | m_keywords.insert (std::pair("if", Token::IF)); 21 | m_keywords.insert (std::pair("else", Token::ELSE)); 22 | m_keywords.insert (std::pair("while", Token::WHILE)); 23 | m_keywords.insert (std::pair("for", Token::FOR)); 24 | m_keywords.insert (std::pair("switch", Token::SWITCH)); 25 | m_keywords.insert (std::pair("case", Token::CASE)); 26 | m_keywords.insert (std::pair("default", Token::DEFAULT)); 27 | m_keywords.insert (std::pair("break", Token::BREAK)); 28 | m_keywords.insert (std::pair("continue", Token::CONTINUE)); 29 | m_keywords.insert (std::pair("return", Token::RETURN)); 30 | m_keywords.insert (std::pair("new", Token::NEW)); 31 | m_keywords.insert (std::pair("nil", Token::NIL)); 32 | m_keywords.insert (std::pair("true", Token::TRUE)); 33 | m_keywords.insert (std::pair("false", Token::FALSE)); 34 | } 35 | 36 | Token Lexer::read_token () 37 | { 38 | Token token; 39 | 40 | while (token.type () == Token::NONE) { 41 | switch (m_buffer[0]) 42 | { 43 | case '(': token = Token (Token::LEFT_PARENTHESES); break; 44 | case ')': token = Token (Token::RIGHT_PARENTHESES); break; 45 | case '[': token = Token (Token::LEFT_BRACKET); break; 46 | case ']': token = Token (Token::RIGHT_BRACKET); break; 47 | case '{': token = Token (Token::LEFT_BRACE); break; 48 | case '}': token = Token (Token::RIGHT_BRACE); break; 49 | case ':': 50 | { 51 | switch (m_buffer[1]) 52 | { 53 | case ':': 54 | { 55 | token = Token (Token::DOUBLE_COLON); 56 | consume (); 57 | } 58 | break; 59 | 60 | default : token = Token (Token::COLON); break; 61 | } 62 | } 63 | break; 64 | 65 | case ';': token = Token (Token::SEMICOLON); break; 66 | case ',': token = Token (Token::COMMA); break; 67 | case '=': 68 | { 69 | switch (m_buffer[1]) 70 | { 71 | case '=': 72 | { 73 | token = Token (Token::EQUALS_EQUALS); 74 | consume (); 75 | } 76 | break; 77 | 78 | default : token = Token (Token::EQUALS); break; 79 | } 80 | } 81 | break; 82 | 83 | case '+': 84 | { 85 | switch (m_buffer[1]) 86 | { 87 | case '=': 88 | { 89 | token = Token (Token::PLUS_EQUALS); 90 | consume (); 91 | } 92 | break; 93 | 94 | case '+': 95 | { 96 | token = Token (Token::INCREMENT); 97 | consume (); 98 | } 99 | break; 100 | 101 | default : token = Token (Token::PLUS); break; 102 | } 103 | } 104 | break; 105 | 106 | case '-': 107 | { 108 | switch (m_buffer[1]) 109 | { 110 | case '=': 111 | { 112 | token = Token(Token::MINUS_EQUALS); 113 | consume (); 114 | } 115 | break; 116 | 117 | case '-': 118 | { 119 | token = Token(Token::DECREMENT); 120 | consume (); 121 | } 122 | break; 123 | 124 | case '>': 125 | { 126 | token = Token(Token::ARROW); 127 | consume (); 128 | } 129 | break; 130 | 131 | default: token = Token(Token::MINUS); break; 132 | } 133 | } 134 | break; 135 | 136 | case '*': 137 | { 138 | switch (m_buffer[1]) 139 | { 140 | case '=': 141 | { 142 | token = Token (Token::TIMES_EQUALS); 143 | consume (); 144 | } 145 | break; 146 | 147 | default : token = Token (Token::TIMES); break; 148 | } 149 | } 150 | break; 151 | 152 | case '/': 153 | { 154 | switch (m_buffer[1]) 155 | { 156 | case '=': 157 | { 158 | token = Token (Token::DIVIDE_EQUALS); 159 | consume (); 160 | } 161 | break; 162 | 163 | // Comment runs until the end of the line 164 | case '/': 165 | { 166 | while (m_buffer[0] != '\n') { 167 | consume (); 168 | } 169 | } 170 | break; 171 | 172 | default : token = Token (Token::DIVIDE); break; 173 | } 174 | } 175 | break; 176 | 177 | case '^': token = Token (Token::EXPONENT); break; 178 | case '%': token = Token (Token::MODULO); break; 179 | 180 | case '|': 181 | { 182 | switch (m_buffer[1]) 183 | { 184 | case '|': 185 | { 186 | token = Token (Token::OR); 187 | consume (); 188 | } 189 | break; 190 | 191 | default : 192 | { 193 | ThrowSignalError (m_line, m_character, "Lexer : Unexpected character '%c', '|' was expected.", m_buffer[1]); 194 | } 195 | break; 196 | } 197 | } 198 | break; 199 | 200 | case '&': 201 | { 202 | switch (m_buffer[1]) 203 | { 204 | case '&': 205 | { 206 | token = Token (Token::AND); 207 | consume (); 208 | } 209 | break; 210 | 211 | default : 212 | { 213 | ThrowSignalError (m_line, m_character, "Lexer : Unexpected character '%c', '&' was expected.", m_buffer[1]); 214 | } 215 | break; 216 | } 217 | } 218 | break; 219 | 220 | case '!': 221 | { 222 | switch (m_buffer[1]) 223 | { 224 | case '=': 225 | { 226 | token = Token (Token::NOT_EQUALS); 227 | consume (); 228 | } 229 | break; 230 | 231 | default : token = Token (Token::NOT); break; 232 | } 233 | } 234 | break; 235 | 236 | case '>': 237 | { 238 | switch (m_buffer[1]) 239 | { 240 | case '=': 241 | { 242 | token = Token (Token::GREATER_THAN_EQUALS); 243 | consume (); 244 | } 245 | break; 246 | 247 | default : token = Token (Token::GREATER_THAN); break; 248 | } 249 | } 250 | break; 251 | 252 | case '<': 253 | { 254 | switch (m_buffer[1]) 255 | { 256 | case '=': 257 | { 258 | token = Token (Token::LESS_THAN_EQUALS); 259 | consume (); 260 | } 261 | break; 262 | 263 | default : token = Token (Token::LESS_THAN); break; 264 | } 265 | } 266 | break; 267 | 268 | case '"': 269 | { 270 | consume (); 271 | token = Token (Token::STRING, get_string ()); 272 | } 273 | break; 274 | 275 | case ' ': consume (); break; 276 | case '\t': consume (); break; 277 | case '\r': consume (); break; 278 | case '\n': 279 | { 280 | if (m_file.is_eof ()) { 281 | token = Token (Token::END_OF_FILE); 282 | } else { 283 | consume (); 284 | m_line++; 285 | m_character = 0; 286 | } 287 | } 288 | break; 289 | 290 | default: 291 | { 292 | if (isDigit (m_buffer[0])) 293 | token = Token (Token::NUMBER, get_number()); 294 | else if (isAlpha (m_buffer[0])) 295 | { 296 | std::string str = get_identifier (); 297 | 298 | auto iterator = m_keywords.find (str); 299 | if (iterator != m_keywords.end ()) 300 | token = Token (iterator->second, str); 301 | else 302 | token = Token (Token::IDENTIFIER, str); 303 | } 304 | else 305 | ThrowSignalError (m_line, m_character, "Lexer : Unexpected character '%c'.", m_buffer[0]); 306 | 307 | // We don't need to consume, so we just return the token now. 308 | return token; 309 | } 310 | } 311 | } 312 | 313 | consume (); 314 | return token; 315 | } 316 | 317 | uint32_t Lexer::line () const 318 | { 319 | return m_line; 320 | } 321 | 322 | uint32_t Lexer::character () const 323 | { 324 | return m_character; 325 | } 326 | 327 | double Lexer::get_number() 328 | { 329 | std::string buffer = ""; 330 | 331 | while (isDigit(m_buffer[0]) || isNumericModifier(m_buffer[0], -1)) 332 | { 333 | buffer.push_back(m_buffer[0]); 334 | consume(); 335 | } 336 | 337 | double ret = atof(buffer.c_str()); 338 | 339 | if (ret == HUGE_VAL) { 340 | ThrowSignalError (m_line, m_character, "Lexer : numerical value is out of range."); 341 | } 342 | 343 | return ret; 344 | } 345 | 346 | std::string Lexer::get_string () 347 | { 348 | std::string buffer = ""; 349 | 350 | // Save these values so we can warn the user if the string does not terminate 351 | uint32_t line = m_line; 352 | uint32_t character = m_character; 353 | 354 | while (m_buffer[0] != '"') 355 | { 356 | buffer.push_back(m_buffer[0]); 357 | consume (); 358 | if (m_file.is_eof ()) 359 | ThrowSignalError (line, character, "Lexer : String has not been terminated. Expected '\"'"); 360 | } 361 | 362 | return buffer; 363 | } 364 | 365 | std::string Lexer::get_identifier () 366 | { 367 | std::string buffer = ""; 368 | 369 | while (isAlpha (m_buffer[0]) || isDigit (m_buffer[0])) 370 | { 371 | buffer.push_back (m_buffer[0]); 372 | consume (); 373 | } 374 | 375 | return buffer; 376 | } 377 | 378 | void Lexer::consume () 379 | { 380 | m_buffer[0] = m_buffer[1]; 381 | 382 | if (m_file.is_eof ()) 383 | { 384 | m_buffer[0] = '\n'; 385 | m_buffer[1] = '\n'; 386 | } else { 387 | m_buffer[1] = m_file.read (); 388 | m_character++; 389 | } 390 | } 391 | } -------------------------------------------------------------------------------- /signal/Lexer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Error.h" 7 | #include "FileInput.h" 8 | #include "Token.h" 9 | #include "Types.h" 10 | 11 | namespace Signal 12 | { 13 | class Lexer 14 | { 15 | public: 16 | 17 | Lexer (FileInput& file); 18 | 19 | Token read_token (); 20 | 21 | uint32_t line () const; 22 | uint32_t character () const; 23 | 24 | private: 25 | 26 | void consume (); 27 | 28 | double get_number (); 29 | std::string get_string (); 30 | std::string get_identifier (); 31 | 32 | FileInput& m_file; 33 | 34 | // Holds two characters, the current one and the lookahead 35 | int8_t m_buffer[2]; 36 | 37 | // Holds all the keywords and their respected token mappings 38 | std::map m_keywords; 39 | 40 | // For debug output 41 | uint32_t m_line; 42 | uint32_t m_character; 43 | }; 44 | } -------------------------------------------------------------------------------- /signal/Object.cpp: -------------------------------------------------------------------------------- 1 | #include "Object.h" 2 | #include "Scope.h" 3 | #include "Utils.h" 4 | 5 | #include 6 | 7 | namespace Signal 8 | { 9 | /* ----- NUMBER ----- */ 10 | Number::Number (double_t number) 11 | : 12 | m_number (number) 13 | {} 14 | 15 | void Number::set (double_t number) 16 | { 17 | this->m_number = number; 18 | } 19 | 20 | double_t Number::number () const 21 | { 22 | return this->m_number; 23 | } 24 | 25 | Object::Type Number::type () const 26 | { 27 | return Object::NUMBER; 28 | } 29 | 30 | std::string Number::toString() 31 | { 32 | std::stringstream output; 33 | output << this->m_number; 34 | return output.str(); 35 | } 36 | 37 | Number* Number::getNumber() const 38 | { 39 | return const_cast(this); 40 | } 41 | 42 | bool Number::operator==(const Object& rhs) 43 | { 44 | if (Number* num = rhs.getNumber()) 45 | return this->m_number == num->number(); 46 | else if (String* str = rhs.getString()) 47 | { 48 | double_t value; 49 | if (stringToDouble(str->text(), value)) 50 | return this->m_number == value; 51 | return false; 52 | } 53 | else if (rhs.getFalse() || rhs.getNil()) 54 | return this->m_number == 0; 55 | else if (rhs.getTrue()) 56 | return this->m_number != 0; 57 | throw this->operatorError(*((Object*)&rhs), "=="); 58 | } 59 | bool Number::operator!=(const Object& rhs) 60 | { 61 | return !(*this == rhs); 62 | } 63 | bool Number::operator< (const Object& rhs) 64 | { 65 | if (Number* num = rhs.getNumber()) 66 | return this->m_number < num->number(); 67 | else if (String* str = rhs.getString()) 68 | { 69 | double_t value; 70 | if (stringToDouble(str->text(), value)) 71 | return this->m_number < value; 72 | return false; 73 | } 74 | throw this->operatorError(*((Object*)&rhs), "<"); 75 | } 76 | bool Number::operator> (const Object& rhs) 77 | { 78 | if (Number* num = rhs.getNumber()) 79 | return this->m_number > num->number(); 80 | else if (String* str = rhs.getString()) 81 | { 82 | double_t value; 83 | if (stringToDouble(str->text(), value)) 84 | return this->m_number > value; 85 | return false; 86 | } 87 | throw this->operatorError(*((Object*)&rhs), ">"); 88 | } 89 | bool Number::operator<=(const Object& rhs) 90 | { 91 | if (Number* num = rhs.getNumber()) 92 | return this->m_number <= num->number(); 93 | else if (String* str = rhs.getString()) /* maybe this is too loose? */ 94 | return this->m_number <= atoi(str->text().c_str()); 95 | throw this->operatorError(*((Object*)&rhs), "<="); 96 | } 97 | bool Number::operator>=(const Object& rhs) 98 | { 99 | return !(*this <= rhs); 100 | } 101 | 102 | /* ----- STRING ----- */ 103 | String::String (const std::string& text) 104 | : 105 | m_text (unescape(text)) 106 | {} 107 | 108 | void String::set (const std::string& text) 109 | { 110 | m_text = unescape(text); 111 | } 112 | 113 | const std::string& String::text () const 114 | { 115 | return m_text; 116 | } 117 | 118 | Object::Type String::type () const 119 | { 120 | return Object::STRING; 121 | } 122 | 123 | std::string String::toString() 124 | { 125 | return m_text; 126 | } 127 | 128 | String* String::getString() const 129 | { 130 | return const_cast(this); 131 | } 132 | 133 | bool String::operator==(const Object& rhs) 134 | { 135 | if (Number* num = rhs.getNumber()) 136 | return (*((Object*)&rhs) == *((Object*)this)); 137 | else if (String* str = rhs.getString()) 138 | return (this->m_text.compare(str->text()) == 0); 139 | else if (rhs.getFalse() || rhs.getNil()) 140 | return false; 141 | else if (rhs.getTrue()) 142 | return true; 143 | throw this->operatorError(*((Object*)&rhs), "=="); 144 | } 145 | bool String::operator!=(const Object& rhs) 146 | { 147 | return !(*this == rhs); 148 | } 149 | bool String::operator< (const Object& rhs) 150 | { 151 | if (Number* num = rhs.getNumber()) 152 | return (*((Object*)&rhs) < *((Object*)this)); 153 | else if (String* str = rhs.getString()) /* maybe this is too loose? */ 154 | return (this->m_text.compare(str->text()) < 0); 155 | 156 | throw this->operatorError(*((Object*)&rhs), "<"); 157 | } 158 | bool String::operator> (const Object& rhs) 159 | { 160 | if (Number* num = rhs.getNumber()) 161 | return (*((Object*)&rhs) > *((Object*)this)); 162 | else if (String* str = rhs.getString()) /* maybe this is too loose? */ 163 | return (this->m_text.compare(str->text()) > 0); 164 | throw this->operatorError(*((Object*)&rhs), "<"); 165 | } 166 | bool String::operator<=(const Object& rhs) 167 | { 168 | if (Number* num = rhs.getNumber()) 169 | return (*((Object*)&rhs) <= *((Object*)this)); 170 | else if (String* str = rhs.getString()) /* maybe this is too loose? */ 171 | return (this->m_text.compare(str->text()) <= 0); 172 | throw this->operatorError(*((Object*)&rhs), "<="); 173 | } 174 | bool String::operator>=(const Object& rhs) 175 | { 176 | return !(*this <= rhs); 177 | } 178 | 179 | 180 | /* ----- INSTANCE ----- */ 181 | Instance::Instance(std::shared_ptr _class) 182 | : 183 | m_class (_class) 184 | { 185 | m_scope = std::shared_ptr (new Scope (*m_class->scope ())); 186 | } 187 | 188 | std::shared_ptr Instance::_class() const 189 | { 190 | return m_class; 191 | } 192 | 193 | std::shared_ptr Instance::scope () const 194 | { 195 | return m_scope; 196 | } 197 | 198 | Object::Type Instance::type () const 199 | { 200 | return Object::INSTANCE; 201 | } 202 | 203 | bool Instance::operator==(const Object& rhs) 204 | { 205 | if (Instance* inst = rhs.getInstance()) 206 | return (this->m_scope.get() == inst->scope().get()); 207 | throw this->operatorError(*((Object*)&rhs), "=="); 208 | } 209 | bool Instance::operator!=(const Object& rhs) 210 | { 211 | return !(*this == rhs); 212 | } 213 | 214 | Class::Class (const std::string& name) 215 | : 216 | m_name (name), 217 | m_scope (new Scope ()) 218 | {} 219 | 220 | Class::Class (const std::string& name, std::shared_ptr base) 221 | : 222 | m_name (name), 223 | m_base (base), 224 | m_scope (new Scope ()) 225 | {} 226 | 227 | const std::string& Class::name () const 228 | { 229 | return m_name; 230 | } 231 | 232 | std::shared_ptr Class::base () const 233 | { 234 | return m_base; 235 | } 236 | 237 | std::shared_ptr Class::scope () const 238 | { 239 | return m_scope; 240 | } 241 | 242 | void Class::add_func(std::shared_ptr func) 243 | { 244 | m_funcs.push_back(func); 245 | func->scope()->setParent(this->scope()); 246 | } 247 | 248 | std::shared_ptr Class::find_func (const std::string& name) const 249 | { 250 | std::shared_ptr ret; 251 | 252 | for (uint32_t i = 0; i < m_funcs.size (); i++) { 253 | if (name == m_funcs[i]->name ()) { 254 | ret = m_funcs[i]; 255 | } 256 | } 257 | 258 | if (ret.get () == nullptr) { 259 | return (m_base.get () == nullptr)? std::shared_ptr () : m_base->find_func (name); 260 | } 261 | 262 | return ret; 263 | } 264 | 265 | Function::Function (const std::string& name) 266 | : 267 | m_name (name), 268 | m_scope (new Scope ()), 269 | m_code (new CodeBlock ()) 270 | {} 271 | 272 | Function::Function (const std::string& name, const std::vector& args) 273 | : 274 | m_name (name), 275 | m_args (args), 276 | m_scope (new Scope ()), 277 | m_code (new CodeBlock ()) 278 | { 279 | for (uint32_t i = 0; i < m_args.size (); i++) { 280 | m_scope->define (m_args[i]); 281 | } 282 | } 283 | 284 | const std::string& Function::name () const 285 | { 286 | return m_name; 287 | } 288 | 289 | const std::vector& Function::args () const 290 | { 291 | return m_args; 292 | } 293 | 294 | std::shared_ptr Function::code () const 295 | { 296 | return m_code; 297 | } 298 | 299 | std::shared_ptr Function::scope () const 300 | { 301 | return m_scope; 302 | } 303 | 304 | void Function::set_scope (std::shared_ptr scope) 305 | { 306 | m_scope = scope; 307 | } 308 | } -------------------------------------------------------------------------------- /signal/Object.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Code.h" 7 | #include "Types.h" 8 | #include "Error.h" 9 | 10 | namespace Signal 11 | { 12 | class Class; 13 | class Function; 14 | class Scope; 15 | class Scope; 16 | 17 | class Number; 18 | class String; 19 | class Instance; 20 | class Nil; 21 | class True; 22 | class False; 23 | 24 | class Object 25 | { 26 | public: 27 | 28 | enum Type 29 | { 30 | NUMBER, 31 | STRING, 32 | INSTANCE, 33 | TRUE, 34 | FALSE, 35 | NIL 36 | }; 37 | 38 | virtual Type type () const = 0; 39 | std::string typeName() 40 | { 41 | switch (this->type()) 42 | { 43 | case NUMBER: return "number"; 44 | case STRING: return "number"; 45 | case INSTANCE: return "instance"; 46 | case NIL: return "nil"; 47 | case TRUE: 48 | case FALSE: 49 | return "boolean"; 50 | } 51 | } 52 | virtual std::string toString() { return ""; } 53 | 54 | virtual Number* getNumber() const { return nullptr; } 55 | virtual String* getString() const { return nullptr; } 56 | virtual Instance* getInstance() const { return nullptr; } 57 | virtual Nil* getNil() const { return nullptr; } 58 | virtual True* getTrue() const { return nullptr; } 59 | virtual False* getFalse() const { return nullptr; } 60 | 61 | virtual bool operator==(const Object& rhs){ throw this->operatorError(*((Object*)&rhs), "=="); } 62 | virtual bool operator!=(const Object& rhs){ throw this->operatorError(*((Object*)&rhs), "!="); } 63 | virtual bool operator< (const Object& rhs){ throw this->operatorError(*((Object*)&rhs), "<"); } 64 | virtual bool operator> (const Object& rhs){ throw this->operatorError(*((Object*)&rhs), ">"); } 65 | virtual bool operator<=(const Object& rhs){ throw this->operatorError(*((Object*)&rhs), "<="); } 66 | virtual bool operator>=(const Object& rhs){ throw this->operatorError(*((Object*)&rhs), ">="); } 67 | 68 | protected: 69 | Error operatorError(Object& rhs, const char* op) 70 | { 71 | return Error("Operator '%s' : Cannot compare object of type '%s' to object of type '%s'", op, this->typeName().c_str(), rhs.typeName().c_str()); 72 | } 73 | }; 74 | 75 | class Number : public Object 76 | { 77 | public: 78 | 79 | Number (double_t number); 80 | 81 | void set (double_t number); 82 | double_t number () const; 83 | 84 | Type type () const; 85 | 86 | virtual std::string toString(); 87 | virtual Number* getNumber() const; 88 | 89 | virtual bool operator==(const Object& rhs); 90 | virtual bool operator!=(const Object& rhs); 91 | virtual bool operator< (const Object& rhs); 92 | virtual bool operator> (const Object& rhs); 93 | virtual bool operator<=(const Object& rhs); 94 | virtual bool operator>=(const Object& rhs); 95 | 96 | private: 97 | double_t m_number; 98 | }; 99 | 100 | class String : public Object 101 | { 102 | public: 103 | 104 | String (const std::string& text); 105 | 106 | void set (const std::string& text); 107 | const std::string& text () const; 108 | 109 | Type type () const; 110 | virtual std::string toString(); 111 | virtual String* getString() const; 112 | 113 | virtual bool operator==(const Object& rhs); 114 | virtual bool operator!=(const Object& rhs); 115 | virtual bool operator< (const Object& rhs); 116 | virtual bool operator> (const Object& rhs); 117 | virtual bool operator<=(const Object& rhs); 118 | virtual bool operator>=(const Object& rhs); 119 | 120 | private: 121 | 122 | std::string m_text; 123 | }; 124 | 125 | class Instance : public Object 126 | { 127 | public: 128 | 129 | Instance (std::shared_ptr _class); 130 | 131 | std::shared_ptr scope () const; 132 | 133 | Type type () const; 134 | std::shared_ptr _class() const; 135 | 136 | virtual Instance* getInstance() const { return const_cast(this); } 137 | 138 | virtual bool operator==(const Object& rhs); 139 | virtual bool operator!=(const Object& rhs); 140 | 141 | private: 142 | 143 | std::shared_ptr m_class; 144 | std::shared_ptr m_scope; 145 | }; 146 | 147 | class Nil : public Object 148 | { 149 | public: 150 | 151 | Nil () {} 152 | 153 | Type type () const 154 | { 155 | return Object::NIL; 156 | } 157 | 158 | virtual std::string toString() { return "nil"; } 159 | virtual Nil* getNil() const { return const_cast(this); } 160 | 161 | bool operator==(const Object& rhs) 162 | { 163 | if (rhs.getTrue()) 164 | return false; 165 | else if (rhs.getFalse() || rhs.getNil()) 166 | return true; 167 | else 168 | return (*((Object*)&rhs) == *((Object*)this)); 169 | } 170 | bool operator!=(const Object& rhs) { return !(*this == rhs); } 171 | }; 172 | 173 | class True : public Object 174 | { 175 | public: 176 | 177 | True () {} 178 | 179 | Type type () const 180 | { 181 | return Object::TRUE; 182 | } 183 | virtual std::string toString() { return "true"; } 184 | virtual True* getTrue() const { return const_cast(this); } 185 | 186 | bool operator==(const Object& rhs) 187 | { 188 | if (rhs.getTrue()) 189 | return true; 190 | else if (rhs.getFalse() || rhs.getNil()) 191 | return false; 192 | else 193 | return (*((Object*)&rhs) == *((Object*)this)); 194 | } 195 | bool operator!=(const Object& rhs) { return !(*this == rhs); } 196 | }; 197 | 198 | class False : public Object 199 | { 200 | public: 201 | 202 | False () {} 203 | 204 | Type type () const 205 | { 206 | return Object::FALSE; 207 | } 208 | 209 | virtual std::string toString() { return "false"; } 210 | virtual False* getFalse() const { return const_cast(this); } 211 | 212 | bool operator==(const Object& rhs) 213 | { 214 | if (rhs.getTrue()) 215 | return false; 216 | else if (rhs.getFalse() || rhs.getNil()) 217 | return true; 218 | else 219 | return (*((Object*)&rhs) == *((Object*)this)); 220 | } 221 | bool operator!=(const Object& rhs) { return !(*this == rhs); } 222 | }; 223 | 224 | class Class 225 | { 226 | public: 227 | 228 | Class (const std::string& name); 229 | Class (const std::string& name, std::shared_ptr base); 230 | 231 | const std::string& name () const; 232 | std::shared_ptr base () const; 233 | std::shared_ptr scope () const; 234 | 235 | void add_func (std::shared_ptr func); 236 | 237 | std::shared_ptr find_func (const std::string& name) const; 238 | 239 | private: 240 | 241 | const std::string m_name; 242 | std::shared_ptr m_base; 243 | std::shared_ptr m_scope; 244 | 245 | std::vector> m_funcs; 246 | }; 247 | 248 | class Function 249 | { 250 | public: 251 | 252 | Function (const std::string& name); 253 | Function (const std::string& name, const std::vector& args); 254 | 255 | const std::string& name () const; 256 | const std::vector& args () const; 257 | std::shared_ptr code () const; 258 | std::shared_ptr scope () const; 259 | 260 | void set_scope (std::shared_ptr scope); 261 | 262 | private: 263 | 264 | const std::string m_name; 265 | const std::vector m_args; 266 | 267 | // Function defines its arguments inside of the scope upon construction. 268 | std::shared_ptr m_scope; 269 | std::shared_ptr m_code; 270 | //std::shared_ptr m_statement; 271 | }; 272 | } -------------------------------------------------------------------------------- /signal/Parser.cpp: -------------------------------------------------------------------------------- 1 | #include "Parser.h" 2 | 3 | namespace Signal 4 | { 5 | Parser::Parser (Lexer& lexer) 6 | : m_lexer(lexer), m_loopLevel(0), m_switchLevel(0) 7 | { 8 | // Fill up the buffers 9 | consume (); 10 | consume (); 11 | } 12 | 13 | std::shared_ptr Parser::parse_program () 14 | { 15 | std::vector> class_def; 16 | std::vector> func_decl; 17 | 18 | while (m_buffer[0].type () != Token::END_OF_FILE) { 19 | 20 | switch (m_buffer[0].type ()) 21 | { 22 | case Token::CLASS: 23 | { 24 | consume(); 25 | do_class_def (class_def); 26 | } 27 | break; 28 | case Token::FUNC: 29 | { 30 | consume(); 31 | do_func_decl (func_decl); 32 | } 33 | break; 34 | case Token::SEMICOLON: 35 | consume(); 36 | break; 37 | default: 38 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : Class definition or function declaration expected."); 39 | } 40 | } 41 | 42 | return std::shared_ptr (new AST(class_def, func_decl)); 43 | } 44 | 45 | void Parser::do_class_def (std::vector>& class_def) 46 | { 47 | std::string name = require(Token::IDENTIFIER).text(); 48 | std::string base; 49 | 50 | // Has base class 51 | if (match (Token::COLON)) { 52 | consume (); 53 | base = require (Token::IDENTIFIER).text (); 54 | } 55 | 56 | require (Token::LEFT_BRACE); 57 | 58 | std::vector> memb_def; 59 | 60 | while (!match (Token::RIGHT_BRACE)) { 61 | do_memb_def (memb_def); 62 | } 63 | 64 | require (Token::RIGHT_BRACE); 65 | 66 | if (base.length () != 0) { 67 | class_def.push_back (std::shared_ptr (new ASTClassDef (name, base, memb_def))); 68 | } else { 69 | class_def.push_back (std::shared_ptr (new ASTClassDef (name, memb_def))); 70 | } 71 | 72 | } 73 | 74 | void Parser::do_func_decl (std::vector>& func_decl) 75 | { 76 | std::string name = require (Token::IDENTIFIER).text(); 77 | std::string base; 78 | 79 | // Member function declaration 80 | if (match (Token::DOUBLE_COLON)) { 81 | consume (); 82 | 83 | base = require (Token::IDENTIFIER).text (); 84 | name.swap (base); 85 | } 86 | 87 | require (Token::LEFT_PARENTHESES); 88 | 89 | std::vector args; 90 | 91 | while (!match (Token::RIGHT_PARENTHESES)) { 92 | args.push_back (require (Token::IDENTIFIER).text ()); 93 | 94 | if (match (Token::COMMA)) { 95 | consume (); 96 | 97 | if (!match (Token::IDENTIFIER)) { 98 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : Argument name expected after colon."); 99 | } 100 | } 101 | } 102 | 103 | require (Token::RIGHT_PARENTHESES); 104 | 105 | std::shared_ptr body = do_block (); 106 | 107 | if (base.length () != 0) { 108 | func_decl.push_back (std::shared_ptr (new ASTMFuncDecl (name, base, args, body))); 109 | } else { 110 | func_decl.push_back (std::shared_ptr (new ASTGFuncDecl (name, args, body))); 111 | } 112 | } 113 | 114 | void Parser::do_memb_def (std::vector>& memb_def) 115 | { 116 | std::string name = require(Token::IDENTIFIER).text(); 117 | 118 | // Function definition 119 | if (match (Token::LEFT_PARENTHESES)) { 120 | consume (); 121 | std::vector args; 122 | 123 | while (!match(Token::RIGHT_PARENTHESES)) { 124 | args.push_back (require (Token::IDENTIFIER).text ()); 125 | 126 | if (match(Token::COMMA)) { 127 | consume (); 128 | 129 | if (!match (Token::IDENTIFIER)) { 130 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : Argument name expected after comma."); 131 | } 132 | } 133 | } 134 | 135 | require (Token::RIGHT_PARENTHESES); 136 | require (Token::SEMICOLON); 137 | 138 | memb_def.push_back (std::shared_ptr (new ASTFuncDef (name, args))); 139 | } else { 140 | memb_def.push_back (std::shared_ptr (new ASTVarDef (name))); 141 | 142 | while (match (Token::COMMA)) { 143 | consume (); 144 | name = require (Token::IDENTIFIER).text (); 145 | memb_def.push_back (std::shared_ptr (new ASTVarDef(name))); 146 | } 147 | 148 | require(Token::SEMICOLON); 149 | } 150 | } 151 | 152 | std::shared_ptr Parser::do_stmt () 153 | { 154 | switch (m_buffer[0].type ()) 155 | { 156 | case Token::LEFT_BRACE: return do_block(); break; 157 | case Token::IF : return do_if(); break; 158 | case Token::WHILE : return do_while(); break; 159 | case Token::FOR : return do_for(); break; 160 | case Token::SWITCH : return do_switch(); break; 161 | case Token::BREAK : return do_break(); break; 162 | case Token::CONTINUE : return do_continue(); break; 163 | case Token::RETURN : return do_return(); break; 164 | 165 | default: 166 | { 167 | std::shared_ptr expr = do_expr(); 168 | require(Token::SEMICOLON); 169 | 170 | return std::shared_ptr (new ASTStmtExpr (expr)); 171 | } 172 | } 173 | } 174 | 175 | std::shared_ptr Parser::do_block () 176 | { 177 | require (Token::LEFT_BRACE); 178 | 179 | std::vector> block; 180 | 181 | while (!match (Token::RIGHT_BRACE)) { 182 | if (match (Token::END_OF_FILE)) { 183 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : Right brace expected."); 184 | } 185 | 186 | block.push_back (do_stmt ()); 187 | } 188 | 189 | require (Token::RIGHT_BRACE); 190 | 191 | return std::shared_ptr (new ASTBlock (block)); 192 | } 193 | 194 | std::shared_ptr Parser::do_if () 195 | { 196 | require (Token::IF); 197 | require (Token::LEFT_PARENTHESES); 198 | 199 | std::shared_ptr cond = do_expr (); 200 | 201 | require (Token::RIGHT_PARENTHESES); 202 | 203 | std::shared_ptr if_part = do_stmt (); 204 | std::shared_ptr else_part; 205 | 206 | if (match (Token::ELSE)) { 207 | consume (); 208 | else_part = do_stmt (); 209 | } 210 | 211 | if (else_part.get () == nullptr) { 212 | return std::shared_ptr (new ASTIf (cond, if_part)); 213 | } else { 214 | return std::shared_ptr (new ASTIf (cond, if_part, else_part)); 215 | } 216 | } 217 | 218 | std::shared_ptr Parser::do_while () 219 | { 220 | require(Token::WHILE); 221 | require(Token::LEFT_PARENTHESES); 222 | 223 | std::shared_ptr cond = do_expr(); 224 | 225 | require(Token::RIGHT_PARENTHESES); 226 | 227 | m_loopLevel++; 228 | std::shared_ptr body = do_stmt(); 229 | m_loopLevel--; 230 | 231 | return std::shared_ptr (new ASTWhile (cond, body)); 232 | } 233 | 234 | std::shared_ptr Parser::do_for () 235 | { 236 | require (Token::FOR); 237 | require (Token::LEFT_PARENTHESES); 238 | 239 | std::shared_ptr init = do_expr(); 240 | require (Token::SEMICOLON); 241 | 242 | std::shared_ptr cond = do_expr(); 243 | require (Token::SEMICOLON); 244 | 245 | std::shared_ptr inc = do_expr(); 246 | require (Token::RIGHT_PARENTHESES); 247 | 248 | m_loopLevel++; 249 | std::shared_ptr body = do_stmt(); 250 | m_loopLevel--; 251 | 252 | return std::shared_ptr (new ASTFor (init, cond, inc, body)); 253 | } 254 | 255 | std::shared_ptr Parser::do_switch () 256 | { 257 | require (Token::SWITCH); 258 | 259 | if (m_switchLevel > 0) 260 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : nested switch statements currently unsupported!"); 261 | 262 | require (Token::LEFT_PARENTHESES); 263 | 264 | std::shared_ptr check = do_expr(); 265 | 266 | require(Token::RIGHT_PARENTHESES); 267 | 268 | require(Token::LEFT_BRACE); 269 | 270 | ASTSwitch* switch_stmt = new ASTSwitch(check); 271 | while (!match(Token::RIGHT_BRACE)) 272 | { 273 | if (match(Token::END_OF_FILE)) 274 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : '}' expected!"); 275 | 276 | if (match(Token::DEFAULT)) 277 | { 278 | require(Token::DEFAULT); 279 | require(Token::COLON); 280 | m_switchLevel++; 281 | switch_stmt->addCase(nullptr, do_stmt()); 282 | m_switchLevel--; 283 | if (!match(Token::RIGHT_BRACE)) 284 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : a default case must be the final case in switch statement."); 285 | break; 286 | } 287 | 288 | require(Token::CASE); 289 | std::shared_ptr _case = do_expr(); 290 | if (_case.get() == nullptr) 291 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : identifier expected!"); 292 | require(Token::COLON); 293 | 294 | if (match(Token::CASE) || match(Token::DEFAULT)) 295 | switch_stmt->addCase(_case, nullptr); 296 | else 297 | { 298 | m_switchLevel++; 299 | switch_stmt->addCase(_case, do_stmt()); 300 | m_switchLevel--; 301 | } 302 | } 303 | 304 | require (Token::RIGHT_BRACE); 305 | 306 | if (switch_stmt->cases().size() == 0) 307 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : empty switch statement not allowed!"); 308 | 309 | return std::shared_ptr(switch_stmt); 310 | } 311 | 312 | std::shared_ptr Parser::do_break() 313 | { 314 | require (Token::BREAK); 315 | require (Token::SEMICOLON); 316 | 317 | if (m_loopLevel == 0 && m_switchLevel == 0) 318 | ThrowSignalError(m_lexer.line(), m_lexer.character(), "Parser : break only allowed within loop or switch construct."); 319 | 320 | return std::shared_ptr (new ASTBreak ()); 321 | } 322 | 323 | std::shared_ptr Parser::do_continue() 324 | { 325 | require (Token::CONTINUE); 326 | require (Token::SEMICOLON); 327 | 328 | if (m_loopLevel == 0) 329 | ThrowSignalError(m_lexer.line(), m_lexer.character(), "Parser : continue only allowed within loop construct."); 330 | 331 | return std::shared_ptr (new ASTContinue ()); 332 | } 333 | 334 | std::shared_ptr Parser::do_return() 335 | { 336 | require (Token::RETURN); 337 | std::shared_ptr ret = do_expr(); 338 | require (Token::SEMICOLON); 339 | 340 | return std::shared_ptr (new ASTReturn(ret)); 341 | } 342 | 343 | // Handles "," 344 | std::shared_ptr Parser::do_expr () 345 | { 346 | std::shared_ptr expr = do_expr1 (); 347 | std::vector> expr_list; 348 | expr_list.push_back (expr); 349 | 350 | while (match (Token::COMMA)) { 351 | expr_list.push_back (do_expr1 ()); 352 | } 353 | 354 | return std::shared_ptr (new ASTExpression (expr_list)); 355 | } 356 | 357 | // Handles "=" 358 | std::shared_ptr Parser::do_expr1 () 359 | { 360 | std::shared_ptr expr = do_expr2 (); 361 | 362 | while (match (Token::EQUALS)) { 363 | if (expr->type () != ASTExpression::IDENTIFIER) { 364 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : left side of an assignment must be an lvalue."); 365 | } 366 | 367 | consume(); 368 | std::shared_ptr expr_right = do_expr1 (); 369 | 370 | expr = std::shared_ptr (new ASTAssignment (dynamic_cast(expr.get ())->name (), expr_right)); 371 | } 372 | 373 | return expr; 374 | } 375 | 376 | // Handles "||" 377 | std::shared_ptr Parser::do_expr2 () 378 | { 379 | std::shared_ptr expr = do_expr3 (); 380 | 381 | while (match (Token::OR)) { 382 | consume (); 383 | std::shared_ptr expr_right = do_expr3 (); 384 | 385 | expr = std::shared_ptr (new ASTCompare (ASTCompare::OR, expr, expr_right)); 386 | } 387 | 388 | return expr; 389 | } 390 | 391 | // Handles "&&" 392 | std::shared_ptr Parser::do_expr3 () 393 | { 394 | std::shared_ptr expr = do_expr4 (); 395 | 396 | while (match (Token::AND)) { 397 | consume (); 398 | std::shared_ptr expr_right = do_expr4 (); 399 | 400 | expr = std::shared_ptr (new ASTCompare (ASTCompare::AND, expr, expr_right)); 401 | } 402 | 403 | return expr; 404 | } 405 | 406 | // Handles "==" 407 | // "!=" 408 | std::shared_ptr Parser::do_expr4 () 409 | { 410 | std::shared_ptr expr = do_expr5 (); 411 | 412 | while (match (Token::EQUALS_EQUALS) || match (Token::NOT_EQUALS)) { 413 | switch (m_buffer[0].type ()) 414 | { 415 | case Token::EQUALS_EQUALS: 416 | { 417 | consume (); 418 | std::shared_ptr expr_right = do_expr5 (); 419 | expr = std::shared_ptr (new ASTCompare (ASTCompare::EQUALS_EQUALS, expr, expr_right)); 420 | } 421 | break; 422 | 423 | case Token::NOT_EQUALS: 424 | { 425 | consume (); 426 | std::shared_ptr expr_right = do_expr5 (); 427 | expr = std::shared_ptr (new ASTCompare (ASTCompare::NOT_EQUALS, expr, expr_right)); 428 | } 429 | break; 430 | } 431 | } 432 | 433 | return expr; 434 | } 435 | 436 | // Handles "<" 437 | // ">" 438 | // "<=" 439 | // ">=" 440 | std::shared_ptr Parser::do_expr5 () 441 | { 442 | std::shared_ptr expr = do_expr6 (); 443 | 444 | while (match (Token::LESS_THAN) || match (Token::GREATER_THAN) || match (Token::LESS_THAN_EQUALS) || match (Token::GREATER_THAN_EQUALS)) { 445 | switch (m_buffer[0].type ()) 446 | { 447 | case Token::LESS_THAN: 448 | { 449 | consume (); 450 | std::shared_ptr expr_right = do_expr6 (); 451 | expr = std::shared_ptr (new ASTCompare (ASTCompare::LESS_THAN, expr, expr_right)); 452 | } 453 | break; 454 | 455 | case Token::GREATER_THAN: 456 | { 457 | consume (); 458 | std::shared_ptr expr_right = do_expr6 (); 459 | expr = std::shared_ptr (new ASTCompare (ASTCompare::GREATER_THAN, expr, expr_right)); 460 | } 461 | break; 462 | 463 | case Token::LESS_THAN_EQUALS: 464 | { 465 | consume (); 466 | std::shared_ptr expr_right = do_expr6 (); 467 | expr = std::shared_ptr (new ASTCompare (ASTCompare::LESS_THAN_EQUALS, expr, expr_right)); 468 | } 469 | break; 470 | 471 | case Token::GREATER_THAN_EQUALS: 472 | { 473 | consume (); 474 | std::shared_ptr expr_right = do_expr6 (); 475 | expr = std::shared_ptr (new ASTCompare (ASTCompare::GREATER_THAN_EQUALS, expr, expr_right)); 476 | } 477 | break; 478 | } 479 | } 480 | 481 | return expr; 482 | } 483 | 484 | // Handles "+" 485 | // "-" 486 | std::shared_ptr Parser::do_expr6 () 487 | { 488 | std::shared_ptr expr = do_expr7 (); 489 | 490 | while (match (Token::PLUS) || match (Token::MINUS)) { 491 | switch (m_buffer[0].type ()) 492 | { 493 | case Token::PLUS: 494 | { 495 | consume (); 496 | std::shared_ptr expr_right = do_expr7 (); 497 | expr = std::shared_ptr (new ASTBinaryMathOp (ASTBinaryMathOp::PLUS, expr, expr_right)); 498 | } 499 | break; 500 | 501 | case Token::MINUS: 502 | { 503 | consume (); 504 | std::shared_ptr expr_right = do_expr7 (); 505 | expr = std::shared_ptr (new ASTBinaryMathOp (ASTBinaryMathOp::MINUS, expr, expr_right)); 506 | } 507 | break; 508 | } 509 | } 510 | 511 | return expr; 512 | } 513 | 514 | // Handles "*" 515 | // "/" 516 | std::shared_ptr Parser::do_expr7 () 517 | { 518 | std::shared_ptr expr = do_expr8 (); 519 | 520 | while (match (Token::TIMES) || match (Token::DIVIDE)) { 521 | switch (m_buffer[0].type ()) 522 | { 523 | case Token::TIMES: 524 | { 525 | consume (); 526 | std::shared_ptr expr_right = do_expr8 (); 527 | expr = std::shared_ptr (new ASTBinaryMathOp (ASTBinaryMathOp::TIMES, expr, expr_right)); 528 | } 529 | break; 530 | 531 | case Token::DIVIDE: 532 | { 533 | consume (); 534 | std::shared_ptr expr_right = do_expr8 (); 535 | expr = std::shared_ptr (new ASTBinaryMathOp (ASTBinaryMathOp::DIVIDE, expr, expr_right)); 536 | } 537 | break; 538 | } 539 | } 540 | 541 | return expr; 542 | } 543 | 544 | // Handles "-" 545 | // "!" 546 | // "new" "(" ")" 547 | // ++ 548 | // -- 549 | std::shared_ptr Parser::do_expr8 () 550 | { 551 | std::shared_ptr expr; 552 | 553 | switch (m_buffer[0].type()) 554 | { 555 | case Token::IDENTIFIER: 556 | { 557 | //Token::INCREMENT 558 | expr = do_expr9(); 559 | if (match(Token::INCREMENT) || match(Token::DECREMENT)) 560 | { 561 | ASTUnaryMathOp::OpType optype = match(Token::INCREMENT) ? ASTUnaryMathOp::INCREMENT : ASTUnaryMathOp::DECREMENT; 562 | expr = std::shared_ptr(new ASTUnaryMathOp(optype, expr)); 563 | consume(); 564 | } 565 | } 566 | break; 567 | case Token::MINUS: 568 | { 569 | consume(); 570 | expr = do_expr9 (); 571 | expr = std::shared_ptr (new ASTUnaryMathOp (ASTUnaryMathOp::MINUS, expr)); 572 | } 573 | break; 574 | case Token::NOT: 575 | { 576 | consume (); 577 | expr = do_expr9 (); 578 | expr = std::shared_ptr (new ASTUnaryMathOp (ASTUnaryMathOp::NOT, expr)); 579 | } 580 | break; 581 | case Token::NEW: 582 | { 583 | consume (); 584 | std::string name = require (Token::IDENTIFIER).text (); 585 | 586 | std::vector> args; 587 | 588 | require (Token::LEFT_PARENTHESES); 589 | 590 | while (!match (Token::RIGHT_PARENTHESES)) { 591 | args.push_back (do_expr1 ()); 592 | 593 | if (match (Token::COMMA)) { 594 | consume (); 595 | } 596 | } 597 | 598 | require (Token::RIGHT_PARENTHESES); 599 | 600 | expr = std::shared_ptr (new ASTNew (name, args)); 601 | } 602 | break; 603 | default: 604 | { 605 | expr = do_expr9 (); 606 | } 607 | break; 608 | } 609 | 610 | 611 | return expr; 612 | } 613 | 614 | // Handles "[" "]" 615 | // "(" ")" 616 | // -> "(" ")" 617 | std::shared_ptr Parser::do_expr9 () 618 | { 619 | std::shared_ptr expr = do_expr10 (); 620 | 621 | while (match (Token::LEFT_PARENTHESES) || match (Token::ARROW) || match (Token::LEFT_BRACKET)) { 622 | switch (m_buffer[0].type ()) 623 | { 624 | case Token::LEFT_BRACKET: 625 | { 626 | /*consume (); 627 | if (expr->type () != ASTExpression::IDENTIFIER) 628 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : Table expected."); 629 | 630 | std::shared_ptr tableIndex = do_expr1(); 631 | require(Token::RIGHT_BRACKET); 632 | 633 | expr = std::shared_ptr(new ASTTable(expr, tableIndex));*/ 634 | } 635 | break; 636 | case Token::LEFT_PARENTHESES: 637 | { 638 | consume (); 639 | if (expr->type () != ASTExpression::IDENTIFIER) 640 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : Function call expected."); 641 | 642 | std::vector> args; 643 | 644 | while (!match (Token::RIGHT_PARENTHESES)) { 645 | args.push_back (do_expr1 ()); 646 | 647 | if (match (Token::COMMA)) { 648 | consume (); 649 | } 650 | } 651 | 652 | require (Token::RIGHT_PARENTHESES); 653 | 654 | expr = std::shared_ptr(new ASTGFuncCall (dynamic_cast(expr.get ())->name (), args)); 655 | } 656 | break; 657 | case Token::ARROW: 658 | { 659 | consume (); 660 | if (expr->type () != ASTExpression::IDENTIFIER) 661 | ThrowSignalError(m_lexer.line (), m_lexer.character(), "Parser : Class object expected."); 662 | 663 | std::string func_name = require (Token::IDENTIFIER).text (); 664 | 665 | std::vector> args; 666 | 667 | require (Token::LEFT_PARENTHESES); 668 | 669 | while (!match (Token::RIGHT_PARENTHESES)){ 670 | args.push_back (do_expr1 ()); 671 | 672 | if (match (Token::COMMA)) { 673 | consume (); 674 | } 675 | } 676 | 677 | require (Token::RIGHT_PARENTHESES); 678 | 679 | expr = std::shared_ptr (new ASTMFuncCall (func_name, dynamic_cast(expr.get ())->name(), args)); 680 | } 681 | break; 682 | } 683 | } 684 | 685 | return expr; 686 | } 687 | 688 | // Handles "{" list "}" 689 | // "(" ")" 690 | // 691 | // 692 | // 693 | // "nil" 694 | // "true" 695 | // "false" 696 | std::shared_ptr Parser::do_expr10() 697 | { 698 | switch (m_buffer[0].type()) 699 | { 700 | case Token::LEFT_BRACE: 701 | { 702 | consume(); 703 | 704 | ASTTable* table = new ASTTable(); 705 | while (!match(Token::RIGHT_BRACE)) 706 | { 707 | bool good = true; 708 | if (match(Token::LEFT_BRACKET)) //[key] = expvalue 709 | { 710 | consume(); 711 | if (!match(Token::NUMBER) && !match(Token::STRING)) 712 | ThrowSignalError(m_lexer.line (), m_lexer.character(), "Parser : Expected string or number key for table."); 713 | std::shared_ptr key = do_expr10(); 714 | require (Token::RIGHT_BRACKET); 715 | 716 | require(Token::EQUALS); 717 | std::shared_ptr value = do_expr2(); 718 | 719 | good = table->insertValue(key, value); 720 | } 721 | else 722 | { 723 | std::shared_ptr key = do_expr2(); 724 | if (key->type() == ASTExpression::IDENTIFIER) // key = expvalue || value 725 | { 726 | if (match(Token::EQUALS)) 727 | { 728 | require(Token::EQUALS); 729 | std::shared_ptr value = do_expr2(); 730 | good = table->insertValue(key, value); 731 | } 732 | else 733 | good = table->insertValue(nullptr, key); 734 | } 735 | else // expvalue 736 | good = table->insertValue(nullptr, key); 737 | } 738 | 739 | if (!good) 740 | ThrowSignalError(m_lexer.line (), m_lexer.character(), "Parser : Invalid key/value pair for table (is it a duplicate?)."); 741 | 742 | if (match(Token::COMMA)) 743 | consume(); 744 | } 745 | 746 | table->normalizeValues(); 747 | require (Token::RIGHT_BRACE); 748 | return std::shared_ptr(new ASTNil()); 749 | } 750 | break; 751 | case Token::LEFT_PARENTHESES: 752 | { 753 | consume(); 754 | std::shared_ptr ret = do_expr1 (); 755 | require (Token::RIGHT_PARENTHESES); 756 | return ret; 757 | } 758 | break; 759 | case Token::IDENTIFIER: 760 | { 761 | std::string var = require(Token::IDENTIFIER).text(); 762 | return std::shared_ptr(new ASTIdentifier(var)); 763 | } 764 | break; 765 | case Token::NUMBER: 766 | { 767 | double_t num = require (Token::NUMBER).number(); 768 | return std::shared_ptr(new ASTNumber(num)); 769 | } 770 | break; 771 | case Token::STRING: 772 | { 773 | std::string str = require (Token::STRING).text(); 774 | return std::shared_ptr(new ASTString(str)); 775 | } 776 | break; 777 | case Token::NIL: 778 | { 779 | consume(); 780 | return std::shared_ptr(new ASTNil()); 781 | } 782 | break; 783 | case Token::TRUE: 784 | { 785 | consume(); 786 | return std::shared_ptr(new ASTTrue()); 787 | } 788 | break; 789 | case Token::FALSE: 790 | { 791 | consume(); 792 | return std::shared_ptr(new ASTFalse()); 793 | } 794 | break; 795 | default: 796 | { 797 | ThrowSignalError(m_lexer.line(), m_lexer.character(), "Parser : Primary expression expected."); 798 | } 799 | break; 800 | } 801 | } 802 | 803 | bool Parser::match (Token::Type type) 804 | { 805 | return (m_buffer[0].type () == type); 806 | } 807 | 808 | Token Parser::require (Token::Type type) 809 | { 810 | if (m_buffer[0].type() != type) { 811 | ThrowSignalError(m_lexer.line (), m_lexer.character (), "Parser : '%s' was not expected.", m_buffer[0].type_to_string().c_str()); 812 | } else { 813 | return consume (); 814 | } 815 | } 816 | 817 | Token Parser::consume () 818 | { 819 | Token ret = m_buffer[0]; 820 | 821 | m_buffer[0] = m_buffer[1]; 822 | m_buffer[1] = m_lexer.read_token (); 823 | 824 | return ret; 825 | } 826 | } -------------------------------------------------------------------------------- /signal/Parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AST.h" 4 | #include "Error.h" 5 | #include "Lexer.h" 6 | #include "Token.h" 7 | #include "Types.h" 8 | 9 | namespace Signal 10 | { 11 | class Parser 12 | { 13 | public: 14 | 15 | Parser (Lexer& lexer); 16 | 17 | std::shared_ptr parse_program (); 18 | 19 | private: 20 | void do_class_def (std::vector>& class_def); 21 | void do_func_decl (std::vector>& func_decl); 22 | void do_memb_def (std::vector>& memb_def); 23 | 24 | std::shared_ptr do_stmt (); 25 | std::shared_ptr do_block (); 26 | std::shared_ptr do_if (); 27 | std::shared_ptr do_while (); 28 | std::shared_ptr do_for (); 29 | std::shared_ptr do_switch (); 30 | std::shared_ptr do_break (); 31 | std::shared_ptr do_continue (); 32 | std::shared_ptr do_return (); 33 | 34 | // TODO : Implement modulo, exponent, +=, -=, arrays, ect... 35 | std::shared_ptr do_expr(); 36 | std::shared_ptr do_expr1(); 37 | std::shared_ptr do_expr2(); 38 | std::shared_ptr do_expr3(); 39 | std::shared_ptr do_expr4(); 40 | std::shared_ptr do_expr5(); 41 | std::shared_ptr do_expr6(); 42 | std::shared_ptr do_expr7(); 43 | std::shared_ptr do_expr8(); 44 | std::shared_ptr do_expr9(); 45 | std::shared_ptr do_expr10(); 46 | 47 | bool match (Token::Type type); 48 | Token require (Token::Type type); 49 | Token consume (); 50 | 51 | Lexer& m_lexer; 52 | int m_loopLevel, m_switchLevel; 53 | 54 | Token m_buffer[2]; 55 | }; 56 | } -------------------------------------------------------------------------------- /signal/Scope.cpp: -------------------------------------------------------------------------------- 1 | #include "Scope.h" 2 | 3 | namespace Signal 4 | { 5 | Scope::Scope () 6 | {} 7 | 8 | Scope::Scope (const Scope& copy) 9 | : 10 | m_vars (copy.m_vars) 11 | { 12 | if (copy.parent ().get () != nullptr){ 13 | m_parent = std::shared_ptr (new Scope (*copy.m_parent)); 14 | } 15 | } 16 | 17 | Scope::Scope (std::shared_ptr parent) 18 | : 19 | m_parent (parent) 20 | {} 21 | 22 | void Scope::define (const std::string& name) 23 | { 24 | m_vars[name] = std::shared_ptr (new Nil ()); 25 | } 26 | 27 | void Scope::define (const std::string& name, std::shared_ptr object) 28 | { 29 | m_vars[name] = object; 30 | } 31 | 32 | void Scope::set(const std::string& name, std::shared_ptr object) 33 | { 34 | if (m_vars[name] == nullptr) 35 | { 36 | if (this->m_parent == nullptr) 37 | throw Error ("Scope : Variable '%s' has not been defined.", name.c_str()); 38 | this->m_parent->set(name, object); 39 | } 40 | m_vars[name] = object; 41 | } 42 | 43 | void Scope::clear () 44 | { 45 | m_vars.clear (); 46 | } 47 | 48 | void Scope::reset () 49 | { 50 | for (auto it = m_vars.begin () ; it != m_vars.end (); it++) { 51 | (*it).second = std::shared_ptr (new Nil ()); 52 | } 53 | 54 | } 55 | 56 | std::shared_ptr Scope::find (const std::string& name) 57 | { 58 | auto var = m_vars.find (name); 59 | 60 | if (var == m_vars.end ()) { 61 | if (m_parent != nullptr) { 62 | return m_parent->find (name); 63 | } else { 64 | return (std::shared_ptr ()); 65 | } 66 | } else { 67 | return var->second; 68 | } 69 | } 70 | 71 | std::shared_ptr Scope::parent () const 72 | { 73 | return m_parent; 74 | } 75 | 76 | void Scope::setParent(std::shared_ptr parent) 77 | { 78 | m_parent = parent; 79 | } 80 | } -------------------------------------------------------------------------------- /signal/Scope.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Error.h" 6 | #include "Object.h" 7 | #include "Types.h" 8 | 9 | namespace Signal 10 | { 11 | class Scope 12 | { 13 | public: 14 | 15 | Scope (); 16 | Scope (const Scope& copy); 17 | Scope (std::shared_ptr parent); 18 | 19 | void define (const std::string& name); 20 | void define (const std::string& name, std::shared_ptr object); 21 | void set (const std::string& name, std::shared_ptr object); 22 | 23 | void clear (); 24 | void reset (); 25 | 26 | std::shared_ptr find (const std::string& name); 27 | 28 | std::shared_ptr parent () const; 29 | void setParent(std::shared_ptr parent); 30 | 31 | private: 32 | 33 | std::shared_ptr m_parent; 34 | 35 | std::map> m_vars; 36 | }; 37 | } -------------------------------------------------------------------------------- /signal/Token.cpp: -------------------------------------------------------------------------------- 1 | #include "Token.h" 2 | 3 | namespace Signal 4 | { 5 | Token::Token () 6 | : 7 | m_type (NONE), 8 | m_text (""), 9 | m_number (0) 10 | {} 11 | 12 | Token::Token (Type type) 13 | : 14 | m_type (type), 15 | m_text (""), 16 | m_number (0) 17 | {} 18 | 19 | Token::Token (Type type, std::string text) 20 | : 21 | m_type (type), 22 | m_text (text), 23 | m_number (0) 24 | {} 25 | 26 | Token::Token (Type type, double_t number) 27 | : 28 | m_type (type), 29 | m_text (""), 30 | m_number (number) 31 | {} 32 | 33 | Token::Type Token::type () const 34 | { 35 | return m_type; 36 | } 37 | 38 | const std::string& Token::text () const 39 | { 40 | return m_text; 41 | } 42 | 43 | double_t Token::number () const 44 | { 45 | return m_number; 46 | } 47 | 48 | std::string Token::type_to_string () const 49 | { 50 | switch (m_type) 51 | { 52 | case LEFT_PARENTHESES: return ("("); 53 | case RIGHT_PARENTHESES: return (")"); 54 | 55 | case LEFT_BRACKET: return ("["); 56 | case RIGHT_BRACKET: return ("]"); 57 | case LEFT_BRACE: return ("{"); 58 | case RIGHT_BRACE: return ("}"); 59 | 60 | case COLON: return (":"); 61 | case DOUBLE_COLON: return ("::"); 62 | case SEMICOLON: return (";"); 63 | 64 | case COMMA: return (","); 65 | 66 | case CLASS: return ("class"); 67 | case IF: return ("if"); 68 | case ELSE: return ("else"); 69 | case WHILE: return ("while"); 70 | case FOR: return ("for"); 71 | case SWITCH: return ("switch"); 72 | case CASE: return ("case"); 73 | case DEFAULT: return ("default"); 74 | case BREAK: return ("break"); 75 | case CONTINUE: return ("continue"); 76 | case RETURN: return ("return"); 77 | case NEW: return ("new"); 78 | case NIL: return ("nil"); 79 | case TRUE: return ("true"); 80 | case FALSE: return ("false"); 81 | 82 | case EQUALS: return ("="); 83 | case PLUS_EQUALS: return ("+="); 84 | case MINUS_EQUALS: return ("-="); 85 | case TIMES_EQUALS: return ("*="); 86 | case DIVIDE_EQUALS: return ("/="); 87 | case OR: return ("||"); 88 | case AND: return ("&&"); 89 | case EQUALS_EQUALS: return ("=="); 90 | case NOT_EQUALS: return ("!="); 91 | case LESS_THAN: return ("<"); 92 | case GREATER_THAN: return (">"); 93 | case LESS_THAN_EQUALS: return ("<="); 94 | case GREATER_THAN_EQUALS: return (">="); 95 | case PLUS: return ("+"); 96 | case MINUS: return ("-"); 97 | case TIMES: return ("*"); 98 | case DIVIDE: return ("/"); 99 | case EXPONENT: return ("^"); 100 | case MODULO: return ("%"); 101 | case NOT: return ("!"); 102 | case INCREMENT: return ("++"); 103 | case DECREMENT: return ("--"); 104 | case ARROW: return ("->"); 105 | 106 | case IDENTIFIER: return ("IDENTIFIER"); 107 | case STRING: return ("STRING"); 108 | case NUMBER: return ("NUMBER"); 109 | 110 | default: return ("UNKNOWN"); 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /signal/Token.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Types.h" 6 | 7 | namespace Signal 8 | { 9 | class Token 10 | { 11 | public: 12 | 13 | enum Type 14 | { 15 | NONE = 0, 16 | 17 | LEFT_PARENTHESES, 18 | RIGHT_PARENTHESES, 19 | LEFT_BRACKET, 20 | RIGHT_BRACKET, 21 | LEFT_BRACE, 22 | RIGHT_BRACE, 23 | 24 | COLON, 25 | DOUBLE_COLON, 26 | SEMICOLON, 27 | 28 | COMMA, 29 | 30 | FUNC, 31 | CLASS, 32 | IF, 33 | ELSE, 34 | WHILE, 35 | FOR, 36 | SWITCH, 37 | CASE, 38 | DEFAULT, 39 | BREAK, 40 | CONTINUE, 41 | RETURN, 42 | NEW, 43 | NIL, 44 | TRUE, 45 | FALSE, 46 | 47 | EQUALS, 48 | PLUS_EQUALS, 49 | MINUS_EQUALS, 50 | TIMES_EQUALS, 51 | DIVIDE_EQUALS, 52 | OR, 53 | AND, 54 | EQUALS_EQUALS, 55 | NOT_EQUALS, 56 | LESS_THAN, 57 | GREATER_THAN, 58 | LESS_THAN_EQUALS, 59 | GREATER_THAN_EQUALS, 60 | PLUS, 61 | MINUS, 62 | TIMES, 63 | DIVIDE, 64 | EXPONENT, 65 | MODULO, 66 | NOT, 67 | INCREMENT, 68 | DECREMENT, 69 | ARROW, 70 | 71 | IDENTIFIER, 72 | STRING, 73 | NUMBER, 74 | 75 | END_OF_FILE 76 | }; 77 | 78 | Token (); 79 | Token (Type type); 80 | Token (Type type, std::string text); 81 | Token (Type type, double_t number); 82 | 83 | Type type () const; 84 | const std::string& text () const; 85 | double_t number () const; 86 | 87 | std::string type_to_string () const; 88 | 89 | private: 90 | 91 | Type m_type; 92 | std::string m_text; 93 | double_t m_number; 94 | }; 95 | } -------------------------------------------------------------------------------- /signal/Types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Signal 4 | { 5 | typedef signed __int8 int8_t; 6 | typedef unsigned __int8 uint8_t; 7 | typedef signed __int16 int16_t; 8 | typedef unsigned __int16 uint16_t; 9 | typedef signed __int32 int32_t; 10 | typedef unsigned __int32 uint32_t; 11 | typedef signed __int64 int64_t; 12 | typedef unsigned __int64 uint64_t; 13 | typedef double double_t; 14 | } -------------------------------------------------------------------------------- /signal/VisitorInterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Signal 4 | { 5 | class AST; 6 | class ASTClassDef; 7 | class ASTMFuncDecl; 8 | class ASTGFuncDecl; 9 | class ASTVarDef; 10 | class ASTFuncDef; 11 | class ASTBlock; 12 | class ASTIf; 13 | class ASTWhile; 14 | class ASTFor; 15 | class ASTSwitch; 16 | class ASTBreak; 17 | class ASTContinue; 18 | class ASTReturn; 19 | class ASTStmtExpr; 20 | class ASTExpression; 21 | class ASTAssignment; 22 | class ASTCompare; 23 | class ASTBinaryMathOp; 24 | class ASTUnaryMathOp; 25 | class ASTNew; 26 | class ASTGFuncCall; 27 | class ASTMFuncCall; 28 | class ASTIdentifier; 29 | class ASTNumber; 30 | class ASTString; 31 | class ASTNil; 32 | class ASTTrue; 33 | class ASTFalse; 34 | 35 | class Class; 36 | class Function; 37 | 38 | class VisitorInterface 39 | { 40 | public: 41 | 42 | virtual ~VisitorInterface() {} 43 | 44 | virtual void visit (const AST& ast) = 0; 45 | virtual void visit (const ASTClassDef& class_def) = 0; 46 | virtual void visit (const ASTMFuncDecl& func_decl) = 0; 47 | virtual void visit (const ASTGFuncDecl& func_decl) = 0; 48 | virtual void visit (const ASTVarDef& var_def, std::shared_ptr _class) = 0; 49 | virtual void visit (const ASTFuncDef& func_def, std::shared_ptr _class) = 0; 50 | virtual void visit (const ASTBlock& block, std::shared_ptr func) = 0; 51 | virtual void visit (const ASTIf& if_stmt, std::shared_ptr func) = 0; 52 | virtual void visit (const ASTWhile& while_stmt, std::shared_ptr func) = 0; 53 | virtual void visit (const ASTFor& for_stmt, std::shared_ptr func) = 0; 54 | virtual void visit (const ASTSwitch& switch_stmt, std::shared_ptr func) = 0; 55 | virtual void visit (const ASTBreak& break_stmt, std::shared_ptr func) = 0; 56 | virtual void visit (const ASTContinue& cont_stmt, std::shared_ptr func) = 0; 57 | virtual void visit (const ASTReturn& ret_stmt, std::shared_ptr func) = 0; 58 | virtual void visit (const ASTStmtExpr& expr_stmt, std::shared_ptr func) = 0; 59 | virtual void visit (const ASTExpression& expr, std::shared_ptr func) = 0; 60 | virtual void visit (const ASTAssignment& expr, std::shared_ptr func) = 0; 61 | virtual void visit (const ASTCompare& expr, std::shared_ptr func) = 0; 62 | virtual void visit (const ASTBinaryMathOp& expr, std::shared_ptr func) = 0; 63 | virtual void visit (const ASTUnaryMathOp& expr, std::shared_ptr func) = 0; 64 | virtual void visit (const ASTNew& expr, std::shared_ptr func) = 0; 65 | virtual void visit (const ASTGFuncCall& expr, std::shared_ptr func) = 0; 66 | virtual void visit (const ASTMFuncCall& expr, std::shared_ptr func) = 0; 67 | virtual void visit (const ASTIdentifier& expr, std::shared_ptr func) = 0; 68 | virtual void visit (const ASTNumber& num, std::shared_ptr func) = 0; 69 | virtual void visit (const ASTString& str, std::shared_ptr func) = 0; 70 | virtual void visit (const ASTNil& nil, std::shared_ptr func) = 0; 71 | virtual void visit (const ASTTrue& expr, std::shared_ptr func) = 0; 72 | virtual void visit (const ASTFalse& expr, std::shared_ptr func) = 0; 73 | }; 74 | } -------------------------------------------------------------------------------- /signal/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Compiler.h" 4 | #include "Interpreter.h" 5 | #include "Parser.h" 6 | #include "Enviroment.h" 7 | 8 | using namespace Signal; 9 | 10 | 11 | std::shared_ptr printFunc(Environment env, std::vector> args) 12 | { 13 | if (args.size() != 1) 14 | throw Error ("print() : Print takes 1 parameter."); 15 | std::cout << args[0]->toString(); 16 | 17 | return nullptr; 18 | } 19 | 20 | 21 | int main (int argc, char* argv[]) 22 | { 23 | try 24 | { 25 | std::cout << "Signal v0.1 - Jeremic" << std::endl << std::endl; 26 | std::string name = ""; 27 | 28 | /*if (argc == 2)*/ { 29 | name = "C:\\Users\\DarkstaR\\Documents\\Visual Studio 2010\\Projects\\signal\\Debug\\test.sig";//argv[1]; 30 | 31 | FileInput file (name); 32 | Lexer lexer (file); 33 | Parser parser (lexer); 34 | std::shared_ptr ast = parser.parse_program (); 35 | Environment env = Environment (); 36 | 37 | env.exportFunction("print", printFunc); 38 | 39 | Compiler::Compile(env, ast); 40 | Interpreter interpreter(env); 41 | interpreter.execute (); 42 | } 43 | } 44 | catch (Error& error) 45 | { 46 | if (error.hasPositionInfo()) { 47 | std::cout << "Error on line " << error.getLine() << " around character " << error.getCharacter() << " : " << error.getError(); 48 | } else { 49 | std::cout << error.getError(); 50 | } 51 | if (error.hasInternalInfo()) 52 | std::cout << std::endl << " (" << error.getInternalLine() << ") " << error.getInternalFile(); 53 | } 54 | 55 | return 0; 56 | } -------------------------------------------------------------------------------- /signal/signal.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {8FA068BC-A38F-4B12-8937-EC79845C14BC} 15 | signal 16 | 17 | 18 | 19 | Application 20 | true 21 | MultiByte 22 | 23 | 24 | Application 25 | false 26 | true 27 | MultiByte 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Level3 43 | Disabled 44 | 45 | 46 | true 47 | 48 | 49 | 50 | 51 | Level3 52 | MaxSpeed 53 | true 54 | true 55 | 56 | 57 | true 58 | true 59 | true 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /signal/signal.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | -------------------------------------------------------------------------------- /signal/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | namespace Signal 4 | { 5 | std::string unescape(const std::string& s) 6 | { 7 | std::string res; 8 | std::string::const_iterator it = s.begin(); 9 | while (it != s.end()) 10 | { 11 | char c = *it++; 12 | if (c == '\\' && it != s.end()) 13 | { 14 | switch (*it++) 15 | { 16 | case '\\': c = '\\'; break; 17 | case 'a': c = '\a'; break; 18 | case 'b': c = '\b'; break; 19 | case 'f': c = '\f'; break; 20 | case 'n': c = '\n'; break; 21 | case 'r': c = '\r'; break; 22 | case 't': c = '\t'; break; 23 | case 'v': c = '\v'; break; 24 | // all other escapes 25 | default: 26 | // invalid escape sequence - skip it. alternatively you can copy it as is, throw an exception... 27 | continue; 28 | } 29 | } 30 | res += c; 31 | } 32 | return res; 33 | } 34 | 35 | 36 | bool isDigit(int8_t character) 37 | { 38 | return ((character >= '0') && (character <= '9')); 39 | } 40 | 41 | bool isNumericModifier(int8_t character, uint32_t index) 42 | { 43 | return (character == '.' || (character == '-' && index == 0)); 44 | } 45 | 46 | bool isAlpha(int8_t character) 47 | { 48 | return (((character >= 'a') && (character <= 'z')) || ((character >= 'A') && (character <= 'Z')) || character == '_'); 49 | } 50 | 51 | bool stringToDouble(const std::string& s, double_t& value) 52 | { 53 | for (uint32_t i = 0; i < s.size(); i++) 54 | if (!isDigit(s.data()[i]) && !isNumericModifier(s.data()[i])) 55 | return false; 56 | double_t ret = atof(s.c_str()); 57 | if (ret == HUGE_VAL) 58 | return false; 59 | 60 | value = ret; 61 | return true; 62 | } 63 | } -------------------------------------------------------------------------------- /signal/utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Types.h" 3 | 4 | namespace Signal 5 | { 6 | std::string unescape(const std::string& s); 7 | 8 | bool isDigit(int8_t character); 9 | bool isNumericModifier(int8_t character, uint32_t index = 0); 10 | bool isAlpha(int8_t character); 11 | 12 | bool stringToDouble(const std::string& s, double_t& value); 13 | } --------------------------------------------------------------------------------