├── lib ├── Lexer │ ├── Name.cpp │ ├── TokenStream.cpp │ └── Lexer.cpp ├── Basic │ ├── Diagnostic.cpp │ └── TokenKinds.cpp ├── Driver │ └── Driver.cpp ├── CodeGen │ ├── Types.cpp │ ├── Decls.cpp │ ├── Stmts.cpp │ └── Exprs.cpp ├── Sema │ ├── Types.cpp │ └── Stmts.cpp └── Parser │ └── Parser.cpp ├── .gitignore ├── include └── simple │ ├── Basic │ ├── TokenKinds.h │ ├── Name.h │ ├── LLVM.h │ ├── Diagnostic.h │ ├── TokenKinds.def │ └── Diagnostic.def │ ├── Lexer │ ├── Lexer.h │ ├── Token.h │ └── TokenStream.h │ ├── Parser │ └── Parser.h │ └── Driver │ └── Driver.h ├── tests ├── ctors_dtor.txt ├── layouts.txt ├── pointers.txt ├── arrays.txt ├── vcalls.txt ├── unwind.txt ├── aggregates.txt ├── operators.txt ├── strings.txt └── functions.txt ├── LICENSE.txt ├── CMakeLists.txt └── simple.cpp /lib/Lexer/Name.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/Basic/Name.h" 2 | 3 | namespace simple { 4 | 5 | Name *Name::Super = nullptr; 6 | Name *Name::This = nullptr; 7 | Name *Name::New = nullptr; 8 | Name *Name::Delete = nullptr; 9 | Name *Name::Ctor = nullptr; 10 | Name *Name::Dtor = nullptr; 11 | 12 | } // namespace simple -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | build 35 | bin 36 | CMakeFiles -------------------------------------------------------------------------------- /include/simple/Basic/TokenKinds.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_BASIC_TOKENKINDS_H 2 | #define SIMPLE_BASIC_TOKENKINDS_H 3 | 4 | #include "llvm/Support/Compiler.h" 5 | 6 | namespace simple { 7 | 8 | namespace tok { 9 | enum TokenKind : unsigned short { 10 | #define TOK(ID, TEXT) ID, 11 | #include "simple/Basic/TokenKinds.def" 12 | }; 13 | 14 | const char *getKeywordSpelling(TokenKind Kind) LLVM_READONLY; 15 | 16 | const char *toString(TokenKind tok); 17 | } // namespace tok 18 | 19 | } // namespace simple 20 | 21 | #endif -------------------------------------------------------------------------------- /tests/ctors_dtor.txt: -------------------------------------------------------------------------------- 1 | class A { 2 | new(n: int) { 3 | print("A.__ctor("); 4 | print(n); 5 | printLn(")"); 6 | } 7 | 8 | new(s: string) { 9 | print("A.__ctor("""); 10 | print(s); 11 | printLn(""")"); 12 | } 13 | 14 | del() { 15 | printLn("A.__dtor()"); 16 | } 17 | } 18 | 19 | class B extends A { 20 | new() : super(10) { 21 | } 22 | 23 | new(s: string): super(s) { 24 | } 25 | } 26 | 27 | class C { 28 | a: B; 29 | } 30 | 31 | fn main() : float { 32 | let a: A("Hello"); 33 | let b: B("Hi"); 34 | let c: B; 35 | let d: C; 36 | 37 | return 0.0; 38 | } -------------------------------------------------------------------------------- /lib/Basic/Diagnostic.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/Basic/Diagnostic.h" 2 | 3 | using namespace simple; 4 | 5 | namespace { 6 | const char *DiagnosticText[] = { 7 | #define DIAG(ID, Level, Msg) Msg, 8 | #include "simple/Basic/Diagnostic.def" 9 | }; 10 | SourceMgr::DiagKind DiagnosticKind[] = { 11 | #define DIAG(ID, Level, Msg) SourceMgr::DK_##Level, 12 | #include "simple/Basic/Diagnostic.def" 13 | }; 14 | } // namespace 15 | 16 | const char *DiagnosticsEngine::getDiagnosticText(unsigned DiagID) { 17 | return DiagnosticText[DiagID]; 18 | } 19 | 20 | SourceMgr::DiagKind DiagnosticsEngine::getDiagnosticKind(unsigned DiagID) { 21 | return DiagnosticKind[DiagID]; 22 | } -------------------------------------------------------------------------------- /include/simple/Basic/Name.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_BASIC_NAME_H 2 | #define SIMPLE_BASIC_NAME_H 3 | 4 | #include "simple/Basic/LLVM.h" 5 | 6 | namespace simple { 7 | 8 | struct Name { 9 | const char *Id; ///< Name's text 10 | int Kind; ///< Name's kind (one of TokenKind) 11 | size_t Length; ///< Length of the text 12 | 13 | static Name *Super; ///< Name for super keyword 14 | static Name *This; ///< Name for this keyword 15 | static Name *Ctor; ///< Name for constructor 16 | static Name *Dtor; ///< Name for destructor 17 | static Name *New; ///< Name for new keyword 18 | static Name *Delete; ///< Name for delete keyword 19 | }; 20 | 21 | } // namespace simple 22 | 23 | #endif -------------------------------------------------------------------------------- /include/simple/Basic/LLVM.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_BASIC_LLVM_H 2 | #define SIMPLE_BASIC_LLVM_H 3 | 4 | #include 5 | 6 | #include "llvm/ADT/None.h" 7 | #include "llvm/Support/Casting.h" 8 | 9 | namespace llvm { 10 | class SMLoc; 11 | class SourceMgr; 12 | template class StringMap; 13 | class StringRef; 14 | class raw_ostream; 15 | } // namespace llvm 16 | 17 | namespace simple { 18 | using llvm::cast; 19 | using llvm::cast_or_null; 20 | using llvm::dyn_cast; 21 | using llvm::dyn_cast_or_null; 22 | using llvm::isa; 23 | 24 | using llvm::raw_ostream; 25 | using llvm::SMLoc; 26 | using llvm::SourceMgr; 27 | using llvm::StringMap; 28 | using llvm::StringRef; 29 | } // namespace simple 30 | 31 | #endif -------------------------------------------------------------------------------- /lib/Basic/TokenKinds.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/Basic/TokenKinds.h" 2 | 3 | namespace simple { 4 | 5 | const char *tok::getKeywordSpelling(TokenKind Kind) { 6 | switch (Kind) { 7 | #define KEYWORD(ID, TEXT) \ 8 | case ID: \ 9 | return TEXT; 10 | #include "simple/Basic/TokenKinds.def" 11 | default: 12 | break; 13 | } 14 | 15 | return nullptr; 16 | } 17 | 18 | const char* tok::toString(TokenKind Kind) { 19 | static const char *TokenStrings[] = { 20 | #define TOK(ID, TEXT) TEXT, 21 | #include "simple/Basic/TokenKinds.def" 22 | }; 23 | 24 | return TokenStrings[Kind]; 25 | } 26 | 27 | } // namespace simple -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ilya Moiseenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /tests/layouts.txt: -------------------------------------------------------------------------------- 1 | class A { 2 | a: int; 3 | b: int; 4 | } 5 | 6 | class B { 7 | c: int; 8 | d: int; 9 | } 10 | 11 | class C extends A { 12 | virt foo() { 13 | } 14 | 15 | e: int; 16 | } 17 | 18 | fn printIntVal(s: string, val: int) { 19 | print(s); 20 | print(val); 21 | printLn(""); 22 | } 23 | 24 | fn printA(pa: A*) { 25 | printIntVal("A.a=", pa.a); 26 | printIntVal("A.b=", pa.b); 27 | } 28 | 29 | fn printB(pb: B*) { 30 | printIntVal("B.c=", pb.c); 31 | printIntVal("B.d=", pb.d); 32 | } 33 | 34 | fn printC(pc: C*) { 35 | printA(pc); 36 | printIntVal("C.e=", pc.e); 37 | } 38 | 39 | fn main() : float { 40 | let c: C; 41 | let pc: C* = &c; 42 | let pa: A* = pc; 43 | let b: B; 44 | let pb: B* = &b; 45 | 46 | c.a = 10; 47 | c.b = 20; 48 | c.e = 30; 49 | 50 | b.c = 40; 51 | b.d = 50; 52 | 53 | printLn("printA(pa)"); 54 | printA(pa); 55 | 56 | printLn("printA(pc)"); 57 | printA(pc); 58 | 59 | printLn("printC(pc)"); 60 | printC(pc); 61 | 62 | printLn("printB(pb)"); 63 | printB(pb); 64 | 65 | return 0.0; 66 | } -------------------------------------------------------------------------------- /include/simple/Basic/Diagnostic.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_BASIC_DIAGNOSTIC_H 2 | #define SIMPLE_BASIC_DIAGNOSTIC_H 3 | 4 | #include "simple/Basic/LLVM.h" 5 | #include "llvm/ADT/StringRef.h" 6 | #include "llvm/Support/FormatVariadic.h" 7 | #include "llvm/Support/SMLoc.h" 8 | #include "llvm/Support/SourceMgr.h" 9 | #include "llvm/Support/raw_ostream.h" 10 | #include 11 | 12 | namespace simple { 13 | 14 | namespace diag { 15 | enum { 16 | #define DIAG(ID, Level, Msg) ID, 17 | #include "simple/Basic/Diagnostic.def" 18 | }; 19 | } // namespace diag 20 | 21 | class DiagnosticsEngine { 22 | static const char *getDiagnosticText(unsigned DiagID); 23 | static SourceMgr::DiagKind getDiagnosticKind(unsigned DiagID); 24 | 25 | SourceMgr &SrcMgr; 26 | unsigned NumErrors; 27 | 28 | public: 29 | DiagnosticsEngine(SourceMgr &SrcMgr) : SrcMgr(SrcMgr), NumErrors(0) {} 30 | 31 | unsigned numErrors() { return NumErrors; } 32 | 33 | template 34 | void report(SMLoc Loc, unsigned DiagID, Args &&...Arguments) { 35 | std::string Msg = llvm::formatv(getDiagnosticText(DiagID), 36 | std::forward(Arguments)...) 37 | .str(); 38 | SourceMgr::DiagKind Kind = getDiagnosticKind(DiagID); 39 | SrcMgr.PrintMessage(Loc, Kind, Msg); 40 | NumErrors += (Kind == SourceMgr::DK_Error); 41 | exit(-1); 42 | } 43 | }; 44 | 45 | } // namespace simple 46 | 47 | #endif -------------------------------------------------------------------------------- /lib/Lexer/TokenStream.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/Lexer/TokenStream.h" 2 | 3 | namespace simple { 4 | 5 | TokenStream::TokenStream(Lexer *lex) 6 | : Lex(lex), 7 | Head(nullptr), 8 | Tail(nullptr), 9 | ScanDone(false) { 10 | } 11 | 12 | TokenStream::~TokenStream() { 13 | StreamNode *p = Head; 14 | 15 | while (p) { 16 | StreamNode *tmp = p; 17 | p = p->Next; 18 | delete tmp; 19 | } 20 | } 21 | 22 | TokenStream::TokenStreamIterator TokenStream::begin() { 23 | // Check for 1st time usage 24 | if (!Head) { 25 | // Create Head, Tail and read 1st token 26 | StreamNode *p = new StreamNode(nullptr, nullptr); 27 | 28 | Lex->next(p->Tok); 29 | ScanDone = p->Tok.getKind() == tok::EndOfFile; 30 | Tail = Head = p; 31 | } 32 | 33 | return TokenStreamIterator(this, Head); 34 | } 35 | 36 | TokenStream::StreamNode *TokenStream::next(StreamNode *curPos) { 37 | // We should check for 1st scan first 38 | if (!curPos->Next) { 39 | // If end of file reached then we should return curPos again 40 | if (ScanDone) { 41 | return curPos; 42 | } 43 | 44 | // Read next token and adjust Tail 45 | StreamNode *p = new StreamNode(nullptr, Tail); 46 | 47 | Lex->next(p->Tok); 48 | ScanDone = p->Tok.getKind() == tok::EndOfFile; 49 | Tail->Next = p; 50 | Tail = p; 51 | 52 | return Tail; 53 | } else { 54 | // Return previously scanned token 55 | return curPos->Next; 56 | } 57 | } 58 | 59 | } // namespace simple -------------------------------------------------------------------------------- /tests/pointers.txt: -------------------------------------------------------------------------------- 1 | fn check(s: string, a: float, b: float) { 2 | if (a == b) { 3 | print(s); 4 | print(" "); 5 | printLn("Pass"); 6 | } 7 | else { 8 | print(s); 9 | print(" "); 10 | printLn("Fail"); 11 | } 12 | } 13 | 14 | fn main() : float { 15 | { 16 | let a: int = 10; 17 | let p: int* = &a; 18 | let pp: int** = &p; 19 | let ppp: int*** = &pp; 20 | 21 | printLn("pointer operations"); 22 | check("a", a, 10); 23 | check("*p", *p, 10); 24 | check("**pp", **pp, 10); 25 | check("***ppp", ***ppp, 10); 26 | check("p[0]", p[0], 10); 27 | check("pp[0][0]", pp[0][0], 10); 28 | check("ppp[0][0][0]", ppp[0][0][0], 10); 29 | if (p) { 30 | printLn("if (p) Pass"); 31 | } else { 32 | printLn("if (p) Fail"); 33 | } 34 | if (pp) { 35 | printLn("if (pp) Pass"); 36 | } else { 37 | printLn("if (pp) Fail"); 38 | } 39 | if (ppp) { 40 | printLn("if (ppp) Pass"); 41 | } else { 42 | printLn("if (ppp) Fail"); 43 | } 44 | } 45 | printLn(""); 46 | { 47 | let a: int[3]; 48 | 49 | a[0] = 1; 50 | a[1] = 2; 51 | a[2] = 3; 52 | 53 | let p: int* = a; 54 | 55 | printLn("pointer arithmetic"); 56 | check("*++p", *++p, 2); 57 | check("*p++", *p++, 2); 58 | check("*p--", *p--, 3); 59 | check("*--p", *--p, 1); 60 | check("*(p + 2)", *(p + 2), 3); 61 | check("*(&a[2] - 2)", *(&a[2] - 2), 1); 62 | } 63 | 64 | return 0.0; 65 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13.4) 2 | project(simple VERSION 0.1.0) 3 | 4 | 5 | 6 | find_package(LLVM 15 REQUIRED CONFIG) 7 | 8 | # Another sanity check 9 | if(NOT "15" VERSION_EQUAL "${LLVM_VERSION_MAJOR}") 10 | message(FATAL_ERROR "Found LLVM ${LLVM_VERSION_MAJOR}, but need LLVM 14") 11 | endif() 12 | 13 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 14 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 15 | 16 | include_directories(${LLVM_INCLUDE_DIRS}) 17 | add_definitions(${LLVM_DEFINITIONS}) 18 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 19 | include(AddLLVM) 20 | 21 | set(LLVM_LINK_COMPONENTS 22 | BitWriter 23 | Core 24 | ExecutionEngine 25 | MC 26 | MCJIT 27 | Support 28 | nativecodegen 29 | ) 30 | 31 | # Set the build directories 32 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") 33 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") 34 | 35 | add_llvm_executable(simple simple.cpp 36 | lib/Basic/Diagnostic.cpp lib/Basic/TokenKinds.cpp 37 | lib/Driver/Driver.cpp 38 | lib/CodeGen/Decls.cpp lib/CodeGen/Exprs.cpp lib/CodeGen/Stmts.cpp lib/CodeGen/Types.cpp 39 | lib/Lexer/Lexer.cpp lib/Lexer/Name.cpp lib/Lexer/TokenStream.cpp 40 | lib/Sema/Decls.cpp lib/Sema/Exprs.cpp lib/Sema/Stmts.cpp lib/Sema/Types.cpp 41 | lib/Parser/Parser.cpp 42 | ) 43 | 44 | target_include_directories(simple PRIVATE "${PROJECT_SOURCE_DIR}/include") 45 | 46 | set(CPACK_PROJECT_NAME ${PROJECT_NAME}) 47 | set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) 48 | include(CPack) -------------------------------------------------------------------------------- /include/simple/Lexer/Lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_LEXER_LEXER_H 2 | #define SIMPLE_LEXER_LEXER_H 3 | 4 | #include "simple/Basic/Diagnostic.h" 5 | #include "simple/Basic/LLVM.h" 6 | #include "simple/Basic/Name.h" 7 | #include "simple/Lexer/Token.h" 8 | #include "llvm/ADT/StringMap.h" 9 | #include "llvm/ADT/StringRef.h" 10 | #include "llvm/Support/MemoryBuffer.h" 11 | #include "llvm/Support/SourceMgr.h" 12 | 13 | namespace simple { 14 | 15 | class NamesMap { 16 | bool IsInit; 17 | llvm::StringMap HashTable; 18 | 19 | Name *addName(StringRef Id, tok::TokenKind TokenCode); 20 | 21 | public: 22 | NamesMap(): IsInit(false) { } 23 | 24 | void addKeywords(); 25 | 26 | Name *getName(StringRef Id); 27 | }; 28 | 29 | class Lexer { 30 | SourceMgr &SrcMgr; 31 | DiagnosticsEngine &Diags; 32 | 33 | StringRef BufferStart; 34 | const char *CurPos; 35 | 36 | /// CurBuffer - This is the current buffer index we're 37 | /// lexing from as managed by the SourceMgr object. 38 | unsigned CurBuffer = 0; 39 | 40 | static NamesMap IdsMap; 41 | 42 | llvm::SMLoc getLoc(const char *Pos) const { 43 | return llvm::SMLoc::getFromPointer(Pos); 44 | } 45 | 46 | public: 47 | Lexer(SourceMgr &SrcMgr, DiagnosticsEngine &Diags) 48 | : SrcMgr(SrcMgr), Diags(Diags) { 49 | CurBuffer = SrcMgr.getMainFileID(); 50 | BufferStart = SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(); 51 | CurPos = BufferStart.begin(); 52 | IdsMap.addKeywords(); 53 | } 54 | 55 | DiagnosticsEngine &getDiagnostics() const { 56 | return Diags; 57 | } 58 | 59 | void next(Token &Result); 60 | }; 61 | } // namespace simple 62 | 63 | #endif -------------------------------------------------------------------------------- /tests/arrays.txt: -------------------------------------------------------------------------------- 1 | fn check(s: string, a: float, b: float) { 2 | if a == b { 3 | print(s); 4 | print(" "); 5 | printLn("Pass"); 6 | } 7 | else { 8 | print(s); 9 | print(" "); 10 | printLn("Fail"); 11 | } 12 | } 13 | 14 | fn main() : float { 15 | 16 | { 17 | let a: int[10]; 18 | 19 | for let i: int = 0; i < 10; ++i { 20 | a[i] = i; 21 | } 22 | printLn("single dimmension array tests"); 23 | check("a[5] == 5", a[5] == 5, 1); 24 | check("a[5] + a[1] == 6", a[5] + a[1] == 6, 1); 25 | check("a[1] = 2", a[1] = 2, 2); 26 | } 27 | printLn(""); 28 | { 29 | let a: int[5][10][20]; 30 | 31 | for let i: int = 0; i < 20; ++i { 32 | for let j: int = 0; j < 10; ++j { 33 | for let k: int = 0; k < 5; ++k { 34 | a[i][j][k] = i * 10000 + j * 100 + k; 35 | } 36 | } 37 | } 38 | 39 | printLn("multi-dimmension array tests"); 40 | check("a[1][2][3] == 10203", a[1][2][3] == 10203, 1); 41 | check("a[1][2][3]++ == 10203", a[1][2][3]++ == 10203, 1); 42 | check("++a[1][2][3] == 10205", ++a[1][2][3] == 10205, 1); 43 | check("a[1][2][3]-- == 10205", a[1][2][3]-- == 10205, 1); 44 | check("--a[1][2][3] == 10203", --a[1][2][3] == 10203, 1); 45 | 46 | let p: int[5][10]*= a; 47 | 48 | p[10][5][2] = 20; 49 | check("a[10][5][2] == 20", a[10][5][2] == 20, 1); 50 | 51 | let pval: int* = &a[0][0][0]; 52 | 53 | check("pval[2 * 10 * 5 + 3 * 5 + 4] == 20304", pval[2 * 10 * 5 + 3 * 5 + 4] == 20304, 1); 54 | check("pval[2 * 10 * 5 + 3 * 5 + 4] == a[2][3][4]", pval[2 * 10 * 5 + 3 * 5 + 4] == a[2][3][4], 1); 55 | } 56 | 57 | return 0.0; 58 | } -------------------------------------------------------------------------------- /tests/vcalls.txt: -------------------------------------------------------------------------------- 1 | fn check(s: string, a: float, b: float) { 2 | if (a == b) { 3 | print(s); 4 | print(" "); 5 | printLn("Pass"); 6 | } 7 | else { 8 | print(s); 9 | print(" "); 10 | printLn("Fail"); 11 | } 12 | } 13 | 14 | class A { 15 | virt foo() : int { 16 | return 1; 17 | } 18 | 19 | virt bar() : int { 20 | return 1; 21 | } 22 | 23 | virt baz() : int { 24 | return 1; 25 | } 26 | } 27 | 28 | class B extends A { 29 | impl foo() : int { 30 | return super.foo() * 10 + 2; 31 | } 32 | 33 | impl baz() : int { 34 | return super.baz() * 10 + 2; 35 | } 36 | } 37 | 38 | class C extends B { 39 | impl foo() : int { 40 | return super.foo() * 10 + 3; 41 | } 42 | 43 | impl bar() : int { 44 | return super.bar() * 10 + 3; 45 | } 46 | } 47 | 48 | class D extends C { 49 | virt boo() : int { 50 | return 4; 51 | } 52 | 53 | impl baz() : int { 54 | return super.baz() * 10 + 4; 55 | } 56 | } 57 | 58 | class E extends D { 59 | impl foo() : int { 60 | return super.foo() * 10 + 5; 61 | } 62 | 63 | impl boo() : int { 64 | return super.boo() * 10 + 5; 65 | } 66 | } 67 | 68 | fn main() : float { 69 | { 70 | printLn("virtual calls test"); 71 | 72 | let c: C; 73 | 74 | check("c.foo()", c.foo(), 123); 75 | check("c.bar()", c.bar(), 13); 76 | check("c.baz()", c.baz(), 12); 77 | 78 | let e: E; 79 | 80 | check("e.boo()", e.boo(), 45); 81 | 82 | let pa: A* = &e; 83 | 84 | check("pa.foo()", pa.foo(), 1235); 85 | check("pa.bar()", pa.bar(), 13); 86 | check("pa.baz()", pa.baz(), 124); 87 | } 88 | 89 | return 0.0; 90 | } -------------------------------------------------------------------------------- /include/simple/Basic/TokenKinds.def: -------------------------------------------------------------------------------- 1 | #ifndef TOK 2 | #define TOK(ID, TEXT) 3 | #endif 4 | 5 | #ifndef KEYWORD 6 | #define KEYWORD(ID, TEXT) TOK(ID, TEXT) 7 | #endif 8 | 9 | KEYWORD(Int, "int") 10 | KEYWORD(Float, "float") 11 | KEYWORD(String, "string") 12 | KEYWORD(Char, "char") 13 | KEYWORD(Void, "void") 14 | KEYWORD(Def, "fn") 15 | KEYWORD(If, "if") 16 | KEYWORD(Else, "else") 17 | KEYWORD(For, "for") 18 | KEYWORD(While, "while") 19 | KEYWORD(Return, "return") 20 | KEYWORD(Break, "break") 21 | KEYWORD(Continue, "continue") 22 | KEYWORD(Struct, "struct") 23 | KEYWORD(Class, "class") 24 | KEYWORD(Extends, "extends") 25 | KEYWORD(This, "this") 26 | KEYWORD(Super, "super") 27 | KEYWORD(Var, "let") 28 | KEYWORD(New, "new") 29 | KEYWORD(Delete, "del") 30 | KEYWORD(Virtual, "virt") 31 | KEYWORD(Override, "impl") 32 | TOK(Identifier, "identifier") 33 | 34 | TOK(IntNumber, "") 35 | TOK(FloatNumber, "") 36 | TOK(CharLiteral, "") 37 | TOK(StringConstant, "") 38 | 39 | TOK(Plus, "+") 40 | TOK(PlusPlus, "++") 41 | TOK(Minus, "-") 42 | TOK(MinusMinus, "--") 43 | TOK(Not, "!") 44 | TOK(Tilda, "~") 45 | TOK(Mul, "*") 46 | TOK(Div, "/") 47 | TOK(Mod, "%") 48 | TOK(LShift, "<<") 49 | TOK(RShift, ">>") 50 | TOK(LogAnd, "&&") 51 | TOK(LogOr, "||") 52 | TOK(BitAnd, "&") 53 | TOK(BitOr, "|") 54 | TOK(BitXor, "^") 55 | TOK(Less, "<") 56 | TOK(Greater, ">") 57 | TOK(LessEqual, "<=") 58 | TOK(GreaterEqual, ">=") 59 | TOK(Equal, "==") 60 | TOK(NotEqual, "!=") 61 | TOK(Assign, "=") 62 | TOK(Comma, ",") 63 | TOK(Dot, ".") 64 | TOK(Question, "?") 65 | TOK(Colon, ":") 66 | TOK(Semicolon, ";") 67 | TOK(OpenParen, "(") 68 | TOK(CloseParen, ")") 69 | TOK(BlockStart, "{") 70 | TOK(BlockEnd, "}") 71 | TOK(OpenBrace, "[") 72 | TOK(CloseBrace, "]") 73 | 74 | TOK(Invalid, "") 75 | TOK(EndOfFile, "EOF") 76 | 77 | #undef KEYWORD 78 | #undef TOK -------------------------------------------------------------------------------- /simple.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/AST/AST.h" 2 | #include "simple/Lexer/Lexer.h" 3 | #include "simple/Parser/Parser.h" 4 | #include "simple/Basic/Diagnostic.h" 5 | #include "simple/Driver/Driver.h" 6 | 7 | #include "llvm/Support/CommandLine.h" 8 | #include "llvm/Support/Host.h" 9 | #include "llvm/Support/InitLLVM.h" 10 | #include "llvm/Support/TargetSelect.h" 11 | #include "llvm/Support/WithColor.h" 12 | 13 | static llvm::cl::opt InputFilename( 14 | llvm::cl::Positional, 15 | llvm::cl::Required, 16 | llvm::cl::desc("") 17 | ); 18 | 19 | static const char *Head = "simple - Simple language compiler"; 20 | 21 | void printVersion(llvm::raw_ostream &OS) { 22 | OS << " Default target: " 23 | << llvm::sys::getDefaultTargetTriple() << "\n"; 24 | std::string CPU(llvm::sys::getHostCPUName()); 25 | OS << " Host CPU: " << CPU << "\n"; 26 | OS << "\n"; 27 | OS.flush(); 28 | exit(EXIT_SUCCESS); 29 | } 30 | 31 | int main(int Argc, const char **Argv) { 32 | llvm::InitLLVM X(Argc, Argv); 33 | 34 | llvm::InitializeNativeTarget(); 35 | llvm::InitializeNativeTargetAsmPrinter(); 36 | llvm::InitializeNativeTargetAsmParser(); 37 | 38 | llvm::cl::SetVersionPrinter(&printVersion); 39 | llvm::cl::ParseCommandLineOptions(Argc, Argv, Head); 40 | 41 | simple::initJIT(); 42 | 43 | llvm::SourceMgr SrcMgr; 44 | simple::DiagnosticsEngine Diags(SrcMgr); 45 | 46 | std::unique_ptr Mod( 47 | simple::ModuleDeclAST::load(SrcMgr, Diags, InputFilename) 48 | ); 49 | 50 | if (!Mod) { 51 | return -1; 52 | } 53 | 54 | Mod->semantic(); 55 | Mod->generateCode(); 56 | 57 | if (Mod->MainPtr) { 58 | llvm::outs() << "Main return: " << Mod->MainPtr() << "\n"; 59 | llvm::outs().flush(); 60 | } 61 | 62 | simple::TypeAST::clearAllTypes(); 63 | 64 | return 0; 65 | } -------------------------------------------------------------------------------- /include/simple/Lexer/Token.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_LEXER_TOKEN_H 2 | #define SIMPLE_LEXER_TOKEN_H 3 | 4 | #include "simple/Basic/LLVM.h" 5 | #include "simple/Basic/Name.h" 6 | #include "simple/Basic/TokenKinds.h" 7 | #include "llvm/ADT/StringRef.h" 8 | #include "llvm/Support/SMLoc.h" 9 | 10 | namespace simple { 11 | 12 | class Lexer; 13 | 14 | class Token { 15 | friend class Lexer; 16 | 17 | const char *Ptr; 18 | size_t Length; 19 | tok::TokenKind Kind; 20 | 21 | union { 22 | Name *Id; 23 | char *Literal; 24 | char Chr; 25 | }; 26 | 27 | public: 28 | ~Token() { 29 | if (isOneOf(tok::IntNumber, tok::FloatNumber, tok::StringConstant)) { 30 | delete[] Literal; 31 | } 32 | } 33 | 34 | tok::TokenKind getKind() const { return Kind; } 35 | 36 | /// is/isNot - Predicates to check if this token is a 37 | /// specific kind, as in "if (Tok.is(tok::EndOfFile)) 38 | /// {...}". 39 | bool is(tok::TokenKind K) const { return Kind == K; } 40 | bool isNot(tok::TokenKind K) const { return Kind != K; } 41 | bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const { 42 | return is(K1) || is(K2); 43 | } 44 | template 45 | bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, Ts... Ks) const { 46 | return is(K1) || isOneOf(K2, Ks...); 47 | } 48 | 49 | SMLoc getLocation() const { 50 | return SMLoc::getFromPointer(Ptr); 51 | } 52 | 53 | size_t getLength() const { 54 | return Length; 55 | } 56 | 57 | Name *getIdentifier() const { 58 | assert(is(tok::Identifier) && "Cannot get identifier of no-identifier"); 59 | return Id; 60 | } 61 | 62 | StringRef getLiteral() const { 63 | assert(isOneOf(tok::IntNumber, tok::FloatNumber, tok::StringConstant) && 64 | "Cannot get literal data of non-literal"); 65 | return StringRef(Literal, Length); 66 | } 67 | 68 | char getChar() const { 69 | assert(is(tok::CharLiteral) && "Cannot get char literal of non-char literal"); 70 | return Chr; 71 | } 72 | }; 73 | } // namespace simple 74 | 75 | #endif -------------------------------------------------------------------------------- /tests/unwind.txt: -------------------------------------------------------------------------------- 1 | class Printer { 2 | new(n: int) { 3 | N = n; 4 | } 5 | 6 | del() { 7 | print("d"); 8 | print(N); 9 | } 10 | 11 | N: int; 12 | } 13 | 14 | fn Test1(i: int) { 15 | let p1: Printer(1); 16 | 17 | if (i > 10) { 18 | let p2: Printer(2); 19 | 20 | while (i < 20) { 21 | let p3: Printer(3); 22 | 23 | if (i == 15) { 24 | break; 25 | } 26 | 27 | let p4: Printer(4); 28 | 29 | ++i; 30 | } 31 | } 32 | } 33 | 34 | fn Test2(a: int, b: int) : int { 35 | let p1: Printer(1); 36 | let i: int = a; 37 | 38 | while (i < b) { 39 | let p2: Printer(2); 40 | 41 | if (i == 5) { 42 | return 1; 43 | } 44 | 45 | let p3: Printer(3); 46 | 47 | if (i == 6) { 48 | return 2; 49 | } 50 | 51 | ++i; 52 | } 53 | 54 | let p4: Printer(4); 55 | 56 | return b; 57 | } 58 | 59 | fn Test3(a: int, b: int) { 60 | if (a > 0) { 61 | let p1: Printer(1); 62 | let i: int = a; 63 | 64 | while (i < b) { 65 | let p2: Printer(2); 66 | 67 | if (i == 5) { 68 | let p3: Printer(3); 69 | } 70 | else 71 | { 72 | let p4: Printer(4); 73 | 74 | if (i == 11) { 75 | return; 76 | } 77 | } 78 | 79 | ++i; 80 | } 81 | } 82 | 83 | let p5: Printer(5); 84 | } 85 | 86 | fn main() : float { 87 | printLn("Test1(19) - result should be: d4d3d2d1"); 88 | Test1(19); 89 | 90 | printLn(""); 91 | printLn("Test1(18) - result should be: d4d3d4d3d2d1"); 92 | Test1(18); 93 | 94 | printLn(""); 95 | printLn("Test1(15) - result should be: d3d2d1"); 96 | Test1(15); 97 | 98 | printLn(""); 99 | printLn("Test2(1, 4) - result should be: d3d2d3d2d3d2d4d1"); 100 | Test2(1, 4); 101 | 102 | printLn(""); 103 | printLn("Test2(5, 10) - result should be: d2d1"); 104 | Test2(5, 10); 105 | 106 | printLn(""); 107 | printLn("Test3(4, 10) - result should be: d4d2d3d2d4d2d4d2d4d2d4d2d1d5"); 108 | Test3(4, 10); 109 | 110 | printLn(""); 111 | printLn("Test3(8, 12) - result should be: d4d2d4d2d4d2d4d2d1"); 112 | Test3(8, 12); 113 | 114 | printLn(""); 115 | return 0.0; 116 | } -------------------------------------------------------------------------------- /include/simple/Parser/Parser.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_PARSER_PARSER_H 2 | #define SIMPLE_PARSER_PARSER_H 3 | 4 | #include "simple/AST/AST.h" 5 | #include "simple/Basic/TokenKinds.h" 6 | #include "simple/Lexer/Lexer.h" 7 | #include "simple/Lexer/TokenStream.h" 8 | 9 | namespace simple { 10 | 11 | /// Parser 12 | class Parser { 13 | /// Source stream iterator 14 | typedef TokenStream::iterator iterator; 15 | 16 | TokenStream Src; ///< Source stream 17 | iterator CurPos; ///< Current position 18 | 19 | DiagnosticsEngine& getDiagnostics() const { 20 | return Src.getDiagnostics(); 21 | } 22 | 23 | public: 24 | /// Constructor 25 | /// \param[in] buffer - content of a source file 26 | Parser(Lexer *lex); 27 | 28 | /// Parse primary expression 29 | ExprAST *parsePrimaryExpr(); 30 | 31 | /// Parse postfix expression 32 | ExprAST *parsePostfixExpr(); 33 | 34 | /// Parse unary expression 35 | ExprAST *parseUnaryExpr(); 36 | 37 | /// Parse right operand of an expression 38 | /// \param[in] lhs - left operand 39 | /// \param[in] maxPrec - max allowed operator precedence 40 | ExprAST *parseRHS(ExprAST *lhs, int maxPrec); 41 | 42 | /// Parse assignment expression 43 | ExprAST *parseAssignExpr(); 44 | 45 | /// Parse comma delimited list of expressions 46 | ExprAST *parseExpr(); 47 | 48 | /// Parse type 49 | TypeAST *parseType(); 50 | 51 | /// Parse module 52 | ModuleDeclAST *parseModule(); 53 | 54 | /// Parse function declaration 55 | /// \param[in] isClassMember - true - if it's class member 56 | SymbolList parseFuncDecl(bool isClassMember); 57 | 58 | /// Parse function's prototype 59 | SymbolAST *parseFuncProto(); 60 | 61 | /// Parse declarations 62 | /// \param[in] isClassMember - true - if it's class member 63 | SymbolList parseDecls(bool isClassMember); 64 | 65 | /// Parse variable declaration 66 | /// \param[in] needSemicolon - true if ; should be at the end of the 67 | /// declaration 68 | /// \param[in] isClassMember - true if it's class/struct member 69 | SymbolList parseDecl(bool needSemicolon, bool isClassMember = false); 70 | 71 | /// Parse statement and add it to block statement if needed 72 | StmtAST *parseStmtAsBlock(); 73 | 74 | /// Parse statement 75 | StmtAST *parseStmt(); 76 | 77 | /// Check iterator for needed token 78 | /// \param[in] tok - needed token 79 | void check(tok::TokenKind tok); 80 | }; 81 | 82 | SymbolAST *parseFuncProto(llvm::StringRef Proto); 83 | 84 | } // namespace simple 85 | 86 | #endif -------------------------------------------------------------------------------- /tests/aggregates.txt: -------------------------------------------------------------------------------- 1 | fn check(s: string, a: float, b: float) { 2 | if a == b { 3 | print(s); 4 | print(" "); 5 | printLn("Pass"); 6 | } 7 | else { 8 | print(s); 9 | print(" "); 10 | printLn("Fail"); 11 | } 12 | } 13 | 14 | fn check(s: string, a: string, b: string) { 15 | if strCmp(a, b) == 0 { 16 | print(s); 17 | print(" "); 18 | printLn("Pass"); 19 | } 20 | else { 21 | print(s); 22 | print(" "); 23 | printLn("Fail"); 24 | } 25 | } 26 | 27 | fn strCmp(str1: string, str2: string) : int { 28 | let p1: string = str1; 29 | let p2: string = str2; 30 | 31 | while (*p1 && *p2) && (*p1 == *p2) { 32 | ++p1; 33 | ++p2; 34 | } 35 | 36 | return *p1 - *p2; 37 | } 38 | 39 | struct A { 40 | a: int; 41 | b: int; 42 | c: float; 43 | } 44 | 45 | class B extends A { 46 | str: string; 47 | } 48 | 49 | class C { 50 | a: A; 51 | b: B; 52 | } 53 | 54 | struct E { 55 | a: A[2]; 56 | } 57 | 58 | struct EE { 59 | a: E[2][2]; 60 | } 61 | 62 | fn main() : float { 63 | { 64 | printLn("aggregate tests"); 65 | 66 | let s: B; 67 | 68 | s.a = 1; 69 | s.b = 2; 70 | s.c = 3.0; 71 | s.str = "Hello"; 72 | 73 | check("s.a", s.a, 1); 74 | check("s.b", s.b, 2); 75 | check("s.c", s.c, 3); 76 | check("s.str", s.str, "Hello"); 77 | } 78 | printLn(""); 79 | { 80 | printLn("compound aggregates tests"); 81 | 82 | let s: C; 83 | 84 | s.a.a = 1; 85 | s.a.b = 2; 86 | s.a.c = 3.0; 87 | s.b.a = 4; 88 | s.b.b = 5; 89 | s.b.c = 6.0; 90 | s.b.str = "Hi"; 91 | 92 | check("s.a.a", s.a.a, 1); 93 | check("s.a.b", s.a.b, 2); 94 | check("s.a.c", s.a.c, 3); 95 | check("s.b.a", s.b.a, 4); 96 | check("s.b.b", s.b.b, 5); 97 | check("s.b.c", s.b.c, 6); 98 | check("s.b.str", s.b.str, "Hi"); 99 | } 100 | printLn(""); 101 | { 102 | printLn("arrays of aggregates tests"); 103 | 104 | let a: A[5]; 105 | 106 | a[0].a = 20; 107 | a[0].b = 2; 108 | a[0].c = 40; 109 | 110 | check("a[0].a", a[0].a, 20); 111 | check("a[0].b", a[0].b, 2); 112 | check("a[0].c", a[0].c, 40); 113 | 114 | let b: E[2]; 115 | 116 | b[0].a[1].a = 21; 117 | b[0].a[1].b = 22; 118 | b[0].a[1].c = 23; 119 | 120 | check("b[0].a[1].a", b[0].a[1].a, 21); 121 | check("b[0].a[1].b", b[0].a[1].b, 22); 122 | check("b[0].a[1].c", b[0].a[1].c, 23); 123 | 124 | check("++b[0].a[1].a", ++b[0].a[1].a, 22); 125 | check("b[0].a[1].b++", b[0].a[1].b++, 22); 126 | 127 | let e: EE[1]; 128 | 129 | e[0].a[0][1].a[0].a = 20; 130 | 131 | check("++e[0].a[0][1].a[0].a", ++e[0].a[0][1].a[0].a, 21); 132 | } 133 | 134 | return 0.0; 135 | } -------------------------------------------------------------------------------- /lib/Driver/Driver.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/Driver/Driver.h" 2 | 3 | using namespace llvm; 4 | 5 | llvm::cl::opt OptimizationLevel(llvm::cl::desc("Choose optimization level:"), 6 | llvm::cl::values( 7 | clEnumValN(NoOptimizations, "O0", "No optimizations"), 8 | clEnumVal(O1, "Enable trivial optimizations"), 9 | clEnumVal(O2, "Enable default optimizations"), 10 | clEnumVal(O3, "Enable expensive optimizations") 11 | ) 12 | ); 13 | 14 | namespace llvm { 15 | namespace orc { 16 | Expected SimpleJIT::optimizeModule(ThreadSafeModule TSM, const MaterializationResponsibility &R) { 17 | TSM.withModuleDo([](Module &M) { 18 | // Create a function pass manager. 19 | auto FPM = std::make_unique(&M); 20 | 21 | // if (OptimizationLevel > NoOptimizations) { 22 | // // Add some optimizations. 23 | // FPM->add(createInstructionCombiningPass()); 24 | // FPM->add(createReassociatePass()); 25 | // FPM->add(createGVNPass()); 26 | // FPM->add(createCFGSimplificationPass()); 27 | // } 28 | 29 | FPM->doInitialization(); 30 | 31 | // Run the optimizations over all functions in the module being added to 32 | // the JIT. 33 | for (auto &F : M) { 34 | FPM->run(F); 35 | } 36 | }); 37 | 38 | return std::move(TSM); 39 | } 40 | } // namespace orc 41 | } // namespace llvm 42 | 43 | namespace simple { 44 | 45 | static std::unique_ptr TheJIT; 46 | static std::unique_ptr TheContext; 47 | static std::unique_ptr> Builder; 48 | static std::unique_ptr TheModule; 49 | static std::unique_ptr TheSLContext; 50 | static ExitOnError ExitOnErr; 51 | 52 | LLVMContext& getGlobalContext() { 53 | return *TheContext.get(); 54 | } 55 | 56 | SLContext& getSLContext() { 57 | return *TheSLContext.get(); 58 | } 59 | 60 | llvm::orc::SimpleJIT& getJIT() { 61 | return *TheJIT.get(); 62 | } 63 | 64 | void initJIT() { 65 | TheJIT = ExitOnErr(llvm::orc::SimpleJIT::Create()); 66 | 67 | // Open a new context and module. 68 | TheContext = std::make_unique(); 69 | TheModule = std::make_unique("simple", *TheContext); 70 | TheModule->setDataLayout(TheJIT->getDataLayout()); 71 | 72 | // Create a new builder for the module. 73 | Builder = std::make_unique>(*TheContext); 74 | 75 | TheSLContext = std::make_unique(); 76 | 77 | TheSLContext->TheTarget = &TheModule->getDataLayout(); 78 | TheSLContext->TheModule = TheModule.get(); 79 | TheSLContext->TheBuilder = Builder.get(); 80 | } 81 | 82 | llvm::JITTargetAddress getJITMain() { 83 | auto TSM = llvm::orc::ThreadSafeModule(std::move(TheModule), std::move(TheContext)); 84 | auto H = TheJIT->addModule(std::move(TSM)); 85 | 86 | // Get the main function's JITSymbol. 87 | auto Sym = ExitOnErr(getJIT().lookup("main")); 88 | 89 | // Get the symbol's address and cast it to the right type (takes no 90 | // arguments, returns a double) so we can call it as a native function. 91 | return Sym.getAddress(); 92 | } 93 | 94 | } // namespace simple -------------------------------------------------------------------------------- /tests/operators.txt: -------------------------------------------------------------------------------- 1 | fn check(s: string, a: float, b: float) { 2 | if (a == b) { 3 | print(s); 4 | print(" "); 5 | printLn("Pass"); 6 | } 7 | else { 8 | print(s); 9 | print(" "); 10 | printLn("Fail"); 11 | } 12 | } 13 | 14 | fn main() : float { 15 | { 16 | let a: int = 10, b: int = 3; 17 | 18 | printLn("integral operations"); 19 | check("-a", -a, -10); 20 | check("+a", +a, 10); 21 | check("!a", !a, 0); 22 | check("~a", ~a, -11); 23 | check("a + b", a + b, 13); 24 | check("a - b", a - b, 7); 25 | check("a * b" , a * b, 30); 26 | check("a / b", a / b, 3); 27 | check("a % b", a % b, 1); 28 | check("a << b", a << b, 80); 29 | check("a >> b", a >> b, 1); 30 | check("a < b", a < b, 0); 31 | check("a <= b", a <= b, 0); 32 | check("a > b", a > b, 1); 33 | check("a >= b", a >= b, 1); 34 | check("a != b", a != b, 1); 35 | check("a == b", a == b, 0); 36 | check("a & b", a & b, 2); 37 | check("a | b", a | b, 11); 38 | check("a ^ b", a ^ b, 9); 39 | check("a || 0", a || 0, 1); 40 | check("0 || a", 0 || a, 1); 41 | check("a && 0", a && 0, 0); 42 | check("a && 1", a && 1, 1); 43 | check("a && b", a && b, 1); 44 | if (a) { 45 | printLn("if (a) Pass"); 46 | } else { 47 | printLn("if (a) Fail"); 48 | } 49 | } 50 | printLn(""); 51 | { 52 | let a: float = 10.0, b: float = 3.0; 53 | 54 | printLn("floating point operations"); 55 | check("-a", -a, -10); 56 | check("+a", +a, 10); 57 | check("!a", !a, 0); 58 | check("a + b", a + b, 13); 59 | check("a - b", a - b, 7); 60 | check("a * b" , a * b, 30); 61 | check("a / b", a / b, 10.0 / 3.0); 62 | check("a % b", a % b, 1); 63 | check("a < b", a < b, 0); 64 | check("a <= b", a <= b, 0); 65 | check("a > b", a > b, 1); 66 | check("a >= b", a >= b, 1); 67 | check("a != b", a != b, 1); 68 | check("a == b", a == b, 0); 69 | check("a || 0", a || 0, 1); 70 | check("0 || a", 0 || a, 1); 71 | check("a && 0", a && 0, 0); 72 | check("a && 1", a && 1, 1); 73 | check("a && b", a && b, 1); 74 | if (a) { 75 | printLn("if (a) Pass"); 76 | } else { 77 | printLn("if (a) Fail"); 78 | } 79 | } 80 | printLn(""); 81 | { 82 | let a: int = 0; 83 | 84 | printLn("increment/decrement operations"); 85 | check("a++", a++, 0); 86 | check("a", a, 1); 87 | check("++a", ++a, 2); 88 | check("a--", a--, 2); 89 | check("a", a, 1); 90 | check("--a", --a, 0); 91 | } 92 | printLn(""); 93 | { 94 | let a: int = 0; 95 | let p: int* = &a; 96 | 97 | printLn("pointer operations"); 98 | check("*p", *p, 0); 99 | a = 10; 100 | check("*p", *p, 10); 101 | check("*p = 2", *p = 2, 2); 102 | } 103 | printLn(""); 104 | { 105 | let a: int = 10, b: int = 20, c: int = 2; 106 | 107 | printLn("other operators"); 108 | check("a, b, c", (a, b, c), 2); 109 | check("a ? b : c", (a ? b : c), 20); 110 | check("(a ? b : c) = 33", (a ? b : c) = 33, 33); 111 | check("b", b, 33); 112 | } 113 | 114 | return 0.0; 115 | } -------------------------------------------------------------------------------- /tests/strings.txt: -------------------------------------------------------------------------------- 1 | fn check(s: string, a: float, b: float) { 2 | if (a == b) { 3 | print(s); 4 | print(" "); 5 | printLn("Pass"); 6 | } 7 | else { 8 | print(s); 9 | print(" "); 10 | printLn("Fail"); 11 | } 12 | } 13 | 14 | fn check(s: string, a: string, b: string) { 15 | if (strCmp(a, b) == 0) { 16 | print(s); 17 | print(" "); 18 | printLn("Pass"); 19 | } 20 | else { 21 | print(s); 22 | print(" "); 23 | printLn("Fail"); 24 | } 25 | } 26 | 27 | fn strLen(str: string) : int { 28 | let length: int = 0; 29 | let p: string = str; 30 | 31 | while (*p) { 32 | ++p, ++length; 33 | } 34 | 35 | return length; 36 | } 37 | 38 | fn strCmp(str1: string, str2: string) : int { 39 | let p1: string = str1; 40 | let p2: string = str2; 41 | 42 | while ((*p1 && *p2) && (*p1 == *p2)) { 43 | ++p1; 44 | ++p2; 45 | } 46 | 47 | return *p1 - *p2; 48 | } 49 | 50 | fn strCpy(dest: char*, src: string) : char* { 51 | let p: char* = dest; 52 | let tmp: string = src; 53 | 54 | while (*tmp) { 55 | *p++ = *tmp++; 56 | } 57 | 58 | *p = *tmp; 59 | 60 | return dest; 61 | } 62 | 63 | fn strCat(dest: char*, src: string) : char* { 64 | let p: char* = dest + strLen(dest); 65 | strCpy(p, src); 66 | return dest; 67 | } 68 | 69 | class String { 70 | new() { 71 | length = 0; 72 | buffSize = 16; 73 | buffer = new char[buffSize]; 74 | buffer[0] = 0; 75 | } 76 | 77 | new(str: string) { 78 | length = strLen(str); 79 | buffSize = length + 1; 80 | buffer = new char[buffSize]; 81 | strCpy(buffer, str); 82 | } 83 | 84 | del() { 85 | del buffer; 86 | } 87 | 88 | fn append(str: string) { 89 | let addLength: int = strLen(str); 90 | 91 | if (addLength + length > buffSize) { 92 | buffSize = addLength + length + 1; 93 | 94 | let newBuffer: char* = new char[buffSize]; 95 | 96 | strCpy(newBuffer, buffer); 97 | del buffer; 98 | buffer = newBuffer; 99 | } 100 | 101 | strCat(buffer + length, str); 102 | length = length + addLength; 103 | } 104 | 105 | fn assign(str: string) { 106 | let addLength: int = strLen(str); 107 | 108 | if (addLength > buffSize) { 109 | buffSize = addLength + 1; 110 | 111 | let newBuffer: char* = new char[buffSize]; 112 | 113 | del buffer; 114 | buffer = newBuffer; 115 | } 116 | 117 | strCpy(buffer, str); 118 | length = length; 119 | } 120 | 121 | fn toString() : string { 122 | return buffer; 123 | } 124 | 125 | length: int; 126 | buffSize: int; 127 | buffer: char*; 128 | } 129 | 130 | fn main() : float { 131 | { 132 | printLn("string functions tests"); 133 | check("strLen(""Hello, world!"")", strLen("Hello, world!"), 13); 134 | check("strCmp(""Hello"", ""Hello"")", strCmp("Hello", "Hello"), 0); 135 | check("strCmp(""Hell"", ""Hello"") < 0", strCmp("Hell", "Hello") < 0, 1); 136 | check("strCmp(""Hello"", ""Hell"") > 0", strCmp("Hello", "Hell") > 0, 1); 137 | 138 | let a: char[20]; 139 | 140 | check("strCpy(a, ""Hello"")", strCpy(a, "Hello"), "Hello"); 141 | check("strCat(a, "", world!"")", strCat(a, ", world!"), "Hello, world!"); 142 | } 143 | printLn(""); 144 | { 145 | printLn("String class tests"); 146 | let str: String("Hello"); 147 | 148 | str.append(", world!"); 149 | 150 | printLn(str.toString()); 151 | 152 | str.assign("Hi"); 153 | 154 | printLn(str.toString()); 155 | } 156 | 157 | return 0.0; 158 | } -------------------------------------------------------------------------------- /include/simple/Driver/Driver.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_DRIVER_DRIVER_H 2 | #define SIMPLE_DRIVER_DRIVER_H 3 | 4 | #include 5 | 6 | #include "simple/Basic/LLVM.h" 7 | 8 | #include "llvm/ADT/StringRef.h" 9 | #include "llvm/ExecutionEngine/JITSymbol.h" 10 | #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 11 | #include "llvm/ExecutionEngine/Orc/Core.h" 12 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 13 | #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" 14 | #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" 15 | #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" 16 | #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" 17 | #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 18 | #include "llvm/ExecutionEngine/SectionMemoryManager.h" 19 | #include "llvm/IR/DataLayout.h" 20 | #include "llvm/IR/IRBuilder.h" 21 | #include "llvm/IR/LLVMContext.h" 22 | #include "llvm/IR/LegacyPassManager.h" 23 | #include "llvm/Support/CommandLine.h" 24 | #include "llvm/Support/Error.h" 25 | #include "llvm/Transforms/InstCombine/InstCombine.h" 26 | #include "llvm/Transforms/Scalar.h" 27 | #include "llvm/Transforms/Scalar/GVN.h" 28 | 29 | 30 | enum OptLevel { 31 | NoOptimizations, O1, O2, O3 32 | }; 33 | 34 | namespace llvm { 35 | namespace orc { 36 | 37 | class SimpleJIT { 38 | private: 39 | std::unique_ptr ES; 40 | 41 | DataLayout DL; 42 | MangleAndInterner Mangle; 43 | 44 | RTDyldObjectLinkingLayer ObjectLayer; 45 | IRCompileLayer CompileLayer; 46 | IRTransformLayer OptimizeLayer; 47 | 48 | JITDylib &MainJD; 49 | 50 | public: 51 | SimpleJIT(std::unique_ptr ES, 52 | JITTargetMachineBuilder JTMB, DataLayout DL) 53 | : ES(std::move(ES)), DL(std::move(DL)), Mangle(*this->ES, this->DL), 54 | ObjectLayer(*this->ES, 55 | []() { return std::make_unique(); }), 56 | CompileLayer(*this->ES, ObjectLayer, 57 | std::make_unique(std::move(JTMB))), 58 | OptimizeLayer(*this->ES, CompileLayer, optimizeModule), 59 | MainJD(this->ES->createBareJITDylib("
")) { 60 | MainJD.addGenerator( 61 | cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( 62 | DL.getGlobalPrefix()))); 63 | } 64 | 65 | ~SimpleJIT() { 66 | if (auto Err = ES->endSession()) { 67 | ES->reportError(std::move(Err)); 68 | } 69 | } 70 | 71 | static Expected> Create() { 72 | auto EPC = SelfExecutorProcessControl::Create(); 73 | 74 | if (!EPC) { 75 | return EPC.takeError(); 76 | } 77 | 78 | auto ES = std::make_unique(std::move(*EPC)); 79 | 80 | JITTargetMachineBuilder JTMB( 81 | ES->getExecutorProcessControl().getTargetTriple()); 82 | 83 | auto DL = JTMB.getDefaultDataLayoutForTarget(); 84 | 85 | if (!DL) { 86 | return DL.takeError(); 87 | } 88 | 89 | return std::make_unique(std::move(ES), std::move(JTMB), 90 | std::move(*DL)); 91 | } 92 | 93 | const DataLayout &getDataLayout() const { return DL; } 94 | 95 | JITDylib &getMainJITDylib() { return MainJD; } 96 | 97 | Error addModule(ThreadSafeModule TSM, ResourceTrackerSP RT = nullptr) { 98 | if (!RT) { 99 | RT = MainJD.getDefaultResourceTracker(); 100 | } 101 | 102 | return OptimizeLayer.add(RT, std::move(TSM)); 103 | } 104 | 105 | Expected lookup(StringRef Name) { 106 | return ES->lookup({&MainJD}, Mangle(Name.str())); 107 | } 108 | 109 | Error addSymbol(StringRef Name, void* Ptr) { 110 | SymbolMap SMap; 111 | 112 | SMap[Mangle(Name)] = JITEvaluatedSymbol( 113 | pointerToJITTargetAddress(Ptr), 114 | JITSymbolFlags() 115 | ); 116 | 117 | return MainJD.define( 118 | absoluteSymbols(std::move(SMap)) 119 | ); 120 | } 121 | 122 | private: 123 | static Expected 124 | optimizeModule(ThreadSafeModule TSM, const MaterializationResponsibility &R); 125 | }; 126 | 127 | } // namespace orc 128 | } // namespace llvm 129 | 130 | namespace simple { 131 | 132 | llvm::LLVMContext& getGlobalContext(); 133 | 134 | struct SLContext { 135 | llvm::Module* TheModule; ///< Current module 136 | llvm::Function* TheFunction; ///< Current function 137 | llvm::IRBuilder< >* TheBuilder; ///< Code builder 138 | // llvm::FunctionPassManager* ThePass; ///< Function's pass 139 | const llvm::DataLayout* TheTarget; ///< Info about target machine 140 | }; 141 | 142 | SLContext& getSLContext(); 143 | 144 | llvm::orc::SimpleJIT& getJIT(); 145 | 146 | void initJIT(); 147 | 148 | llvm::JITTargetAddress getJITMain(); 149 | 150 | } // namespace simple 151 | 152 | #endif -------------------------------------------------------------------------------- /include/simple/Lexer/TokenStream.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_LEXER_TOKENSTREAM_H 2 | #define SIMPLE_LEXER_TOKENSTREAM_H 3 | 4 | #include "simple/Basic/TokenKinds.h" 5 | #include "simple/Lexer/Lexer.h" 6 | #include "simple/Lexer/Token.h" 7 | #include "llvm/Support/SMLoc.h" 8 | 9 | namespace simple { 10 | 11 | /// Stream of tokens 12 | class TokenStream { 13 | /// Stream's node (for double-linked list) 14 | struct StreamNode { 15 | /// Constructor 16 | /// \param[in] next - next node 17 | /// \param[in] prev - previous node 18 | StreamNode(StreamNode *next, StreamNode *prev) 19 | : Next(next), 20 | Prev(prev) { 21 | } 22 | 23 | Token Tok; ///< Token data 24 | StreamNode *Next; ///< Next node 25 | StreamNode *Prev; ///< Previous node 26 | }; 27 | 28 | /// Token's stream iterator 29 | class TokenStreamIterator { 30 | public: 31 | /// Copy constructor 32 | /// \param[in] other - iterator to copy 33 | TokenStreamIterator(const TokenStreamIterator &other) 34 | : CurStream(other.CurStream), 35 | CurPos(other.CurPos) { 36 | } 37 | 38 | /// Assignment operator 39 | /// \param[in] other - iterator to copy 40 | /// \return *this 41 | TokenStreamIterator &operator=(const TokenStreamIterator &other) { 42 | if (&other != this) { 43 | CurStream = other.CurStream; 44 | CurPos = other.CurPos; 45 | } 46 | 47 | return *this; 48 | } 49 | 50 | /// Check for empty iterator 51 | bool empty() const { 52 | return (CurStream == nullptr && CurPos == nullptr); 53 | } 54 | 55 | /// Get location in the source file 56 | llvm::SMLoc getLocation() const { 57 | assert(CurPos); 58 | return CurPos->Tok.getLocation(); 59 | } 60 | 61 | /// Check for token kind equality 62 | bool operator ==(tok::TokenKind tok) const { 63 | return CurPos->Tok.getKind() == tok; 64 | } 65 | 66 | /// Check for token kind inequality 67 | bool operator !=(tok::TokenKind tok) const { 68 | return CurPos->Tok.getKind() != tok; 69 | } 70 | 71 | /// Dereference 72 | const Token &operator *() const { 73 | return CurPos->Tok; 74 | } 75 | 76 | /// Access through pointer member access 77 | const Token *operator ->() const { 78 | return &CurPos->Tok; 79 | } 80 | 81 | /// Post increment 82 | TokenStreamIterator operator ++(int) { 83 | TokenStreamIterator tmp = *this; 84 | ++(*this); 85 | return tmp; 86 | } 87 | 88 | /// Prefix increment 89 | TokenStreamIterator &operator ++() { 90 | CurPos = CurStream->next(CurPos); 91 | return *this; 92 | } 93 | 94 | /// Post decrement 95 | TokenStreamIterator operator --(int) { 96 | TokenStreamIterator tmp = *this; 97 | --(*this); 98 | return tmp; 99 | } 100 | 101 | /// Prefix decrement 102 | TokenStreamIterator &operator --() { 103 | if (CurPos->Prev) { 104 | CurPos = CurPos->Prev; 105 | } 106 | return *this; 107 | } 108 | 109 | /// Advance to \c count tokens 110 | /// \param[in] count - number of token to advance 111 | TokenStreamIterator operator +(int count) { 112 | TokenStreamIterator tmp = *this; 113 | while (count--) { 114 | ++tmp; 115 | } 116 | return tmp; 117 | } 118 | 119 | /// Backward to \c count tokens 120 | /// \param[in] count - number of token to backward 121 | TokenStreamIterator operator -(int count) { 122 | TokenStreamIterator tmp = *this; 123 | while (count--) { 124 | --tmp; 125 | } 126 | return tmp; 127 | } 128 | 129 | friend class TokenStream; 130 | 131 | private: 132 | TokenStream *CurStream; ///< Source stream associated with this iterator 133 | StreamNode *CurPos; ///< Current position in the token stream 134 | 135 | /// Constructor 136 | /// \param[in] source - source stream 137 | /// \param[in] curPos - current position 138 | TokenStreamIterator(TokenStream *source = nullptr, StreamNode *curPos = nullptr) 139 | : CurStream(source), 140 | CurPos(curPos) { 141 | } 142 | }; 143 | 144 | Lexer *Lex; ///< Lexical analyzer with the source file 145 | StreamNode *Head; ///< Head element 146 | StreamNode *Tail; ///< Tail element 147 | bool ScanDone; ///< true - if end of file reached 148 | 149 | /// Read next token 150 | /// \param[in] curPos - current position 151 | /// \return Next token 152 | StreamNode *next(StreamNode *curPos); 153 | 154 | public: 155 | /// Type for iterator 156 | typedef TokenStreamIterator iterator; 157 | 158 | /// Constructor 159 | /// \param[in] lexer - lexical analyzer with the source file 160 | TokenStream(Lexer *lexer); 161 | 162 | /// Destructor 163 | ~TokenStream(); 164 | 165 | DiagnosticsEngine &getDiagnostics() const { 166 | return Lex->getDiagnostics(); 167 | } 168 | 169 | /// Get position of the 1st element 170 | TokenStreamIterator begin(); 171 | }; 172 | 173 | } // namespace simple 174 | 175 | #endif -------------------------------------------------------------------------------- /lib/CodeGen/Types.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/AST/AST.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace simple { 6 | 7 | Type* BuiltinTypeAST::getType() { 8 | static Type* builtinTypes[] = { 9 | Type::getVoidTy(getGlobalContext()), 10 | Type::getInt1Ty(getGlobalContext()), 11 | Type::getInt32Ty(getGlobalContext()), 12 | Type::getDoubleTy(getGlobalContext()), 13 | Type::getInt8Ty(getGlobalContext()), 14 | PointerType::get( 15 | getGlobalContext(), 16 | getSLContext().TheTarget->getProgramAddressSpace() 17 | ) 18 | }; 19 | 20 | if (ThisType) { 21 | return ThisType; 22 | } 23 | 24 | return ThisType = builtinTypes[TypeKind]; 25 | } 26 | 27 | Type* ArrayTypeAST::getType() { 28 | if (ThisType) { 29 | return ThisType; 30 | } 31 | 32 | return ThisType = ArrayType::get(Next->getType(), Dim); 33 | } 34 | 35 | Type* PointerTypeAST::getType() { 36 | if (ThisType) { 37 | return ThisType; 38 | } 39 | 40 | return ThisType = PointerType::get( 41 | getGlobalContext(), 42 | getSLContext().TheTarget->getProgramAddressSpace() 43 | ); 44 | } 45 | 46 | /// Calculate aggregate name 47 | /// \param[in] output - output buffer 48 | /// \param[in] thisSym - aggregate which name we should get 49 | /// \note It will generate names like A.B.C for nested aggregates 50 | void calcAggregateName(llvm::raw_ostream& output, SymbolAST* thisSym) { 51 | assert(thisSym && thisSym->isAggregate()); 52 | SymbolAST* sym = thisSym; 53 | 54 | for ( ; ; ) { 55 | output << StringRef(sym->Id->Id, sym->Id->Length); 56 | sym = sym->Parent; 57 | 58 | if (!sym || !sym->isAggregate()) { 59 | return; 60 | } 61 | 62 | output << "."; 63 | } 64 | } 65 | 66 | Type* StructTypeAST::getType() { 67 | // Calculate type only once 68 | if (ThisType) { 69 | return ThisType; 70 | } 71 | 72 | llvm::SmallString< 128 > s; 73 | llvm::raw_svector_ostream output(s); 74 | 75 | // For struct we always add struct. at it's start 76 | output << "struct."; 77 | calcAggregateName(output, ThisDecl); 78 | 79 | // Note: we should create and assign ThisType now not at the end of the 80 | // function because members can point to this type too 81 | ThisType = StructType::create(getGlobalContext(), output.str()); 82 | 83 | std::vector< Type* > vars; 84 | StructDeclAST* structDecl = (StructDeclAST*)ThisDecl; 85 | 86 | // Fill list of members 87 | for (SymbolList::iterator it = structDecl->Vars.begin(), 88 | end = structDecl->Vars.end(); it != end; ++it) { 89 | vars.push_back(((VarDeclAST*)(*it))->ThisType->getType()); 90 | } 91 | 92 | // If struct has 0 members then we forcedly add member with 1 byte length. 93 | // Because otherwise size of this type will be 0 94 | if (vars.empty()) { 95 | vars.push_back(Type::getInt8Ty(getGlobalContext())); 96 | } 97 | 98 | // Set members of struct and return generated type 99 | ((StructType*)ThisType)->setBody(vars); 100 | return ThisType; 101 | } 102 | 103 | Type* ClassTypeAST::getType() { 104 | if (ThisType) { 105 | return ThisType; 106 | } 107 | 108 | llvm::SmallString< 128 > s; 109 | llvm::raw_svector_ostream output(s); 110 | 111 | // For class we always add class. at it's start 112 | output << "class."; 113 | calcAggregateName(output, ThisDecl); 114 | 115 | // Note: we should create and assign ThisType now not at the end of the 116 | // function because members can point to this type too 117 | ThisType = StructType::create(getGlobalContext(), output.str()); 118 | 119 | std::vector< Type* > vars; 120 | ClassDeclAST* classDecl = (ClassDeclAST*)ThisDecl; 121 | VTableAST* baseVtbl = nullptr; 122 | Type* baseType = nullptr; 123 | 124 | // Check does this class have base class or not 125 | if (classDecl->BaseClass) { 126 | // Check for VTable 1st 127 | if (isa(classDecl->BaseClass)) { 128 | ClassDeclAST* baseDecl = (ClassDeclAST*)classDecl->BaseClass->getSymbol(); 129 | baseVtbl = baseDecl->VTbl; 130 | } 131 | 132 | // Get type of base class 133 | baseType = classDecl->BaseClass->getType(); 134 | } 135 | 136 | if (classDecl->VTbl && !baseVtbl) { 137 | // We have VTable but base class don't. Add VTable slot 138 | // Note: We want VTable always as the first member in the class layout 139 | vars.push_back( 140 | PointerType::get( 141 | getGlobalContext(), 142 | getSLContext().TheTarget->getProgramAddressSpace() 143 | ) 144 | ); 145 | } 146 | 147 | // If we have base class we should add variable with it's type 148 | // Example: 149 | // class A { int a; } 150 | // class B : A { int b; } 151 | // will give 152 | // class.A = { int32 } 153 | // class.B = { class.A, int32 } 154 | if (baseType) { 155 | vars.push_back(baseType); 156 | } 157 | 158 | // Fill list of members 159 | for (SymbolList::iterator it = classDecl->Vars.begin(), 160 | end = classDecl->Vars.end(); it != end; ++it) { 161 | // We need add only variables and not aggregates and functions 162 | if (isa(*it)) { 163 | vars.push_back(((VarDeclAST*)(*it))->ThisType->getType()); 164 | } 165 | } 166 | 167 | // If class has 0 members then we forcedly add member with 1 byte length. 168 | // Because otherwise size of this type will be 0 169 | if (vars.empty()) { 170 | vars.push_back(Type::getInt8Ty(getGlobalContext())); 171 | } 172 | 173 | // Set members of struct and return generated type 174 | ((StructType*)ThisType)->setBody(vars); 175 | return ThisType; 176 | } 177 | 178 | Type* FuncTypeAST::getType() { 179 | // Calculate type only once 180 | if (ThisType) { 181 | return ThisType; 182 | } 183 | 184 | // If ReturnType wasn't set then we set it as void type 185 | Type* returnType = (ReturnType ? ReturnType->getType() : 186 | Type::getVoidTy(getGlobalContext())); 187 | 188 | if (Params.empty()) { 189 | // Return version without parameters 190 | return ThisType = FunctionType::get(returnType, false); 191 | } 192 | 193 | std::vector< Type* > params; 194 | 195 | // Create list of function parameters for llvm 196 | for (ParameterList::iterator it = Params.begin(), end = Params.end(); 197 | it != end; ++it) { 198 | params.push_back((*it)->Param->getType()); 199 | } 200 | 201 | // Return version with parameters 202 | return ThisType = FunctionType::get(returnType, params, false); 203 | } 204 | 205 | Type* QualifiedTypeAST::getType() { 206 | assert(0 && "QualifiedTypeAST::getType should never be reached"); 207 | return nullptr; 208 | } 209 | 210 | } // namespace simple -------------------------------------------------------------------------------- /tests/functions.txt: -------------------------------------------------------------------------------- 1 | fn check(s: string, a: float, b: float) { 2 | if (a == b) { 3 | print(s); 4 | print(" "); 5 | printLn("Pass"); 6 | } 7 | else { 8 | print(s); 9 | print(" "); 10 | printLn("Fail"); 11 | } 12 | } 13 | 14 | fn check(s: string, a: string, b: string) { 15 | if (strCmp(a, b) == 0) { 16 | print(s); 17 | print(" "); 18 | printLn("Pass"); 19 | } 20 | else { 21 | print(s); 22 | print(" "); 23 | printLn("Fail"); 24 | } 25 | } 26 | 27 | fn strCmp(str1: string, str2: string) : int { 28 | let p1: string = str1; 29 | let p2: string = str2; 30 | 31 | while ((*p1 && *p2) && (*p1 == *p2)) { 32 | ++p1; 33 | ++p2; 34 | } 35 | 36 | return *p1 - *p2; 37 | } 38 | 39 | fn foo() : string { 40 | return "foo()"; 41 | } 42 | 43 | fn foo(_: int) : string { 44 | return "foo(int)"; 45 | } 46 | 47 | fn foo(_: float) : string { 48 | return "foo(float)"; 49 | } 50 | 51 | fn foo(_: string) : string { 52 | return "foo(string)"; 53 | } 54 | 55 | class A { 56 | } 57 | 58 | class B extends A { 59 | } 60 | 61 | class C extends B { 62 | } 63 | 64 | class E extends C { 65 | } 66 | 67 | class D { 68 | fn foo() : string { 69 | return "D.foo()"; 70 | } 71 | 72 | fn foo(_: int) : string { 73 | return "D.foo(int)"; 74 | } 75 | 76 | fn foo(_: float) : string { 77 | return "D.foo(float)"; 78 | } 79 | 80 | fn foo(_: string) : string { 81 | return "D.foo(string)"; 82 | } 83 | 84 | fn foo(_: void*) : string { 85 | return "D.foo(void*)"; 86 | } 87 | 88 | fn foo(_: A*) : string { 89 | return "D.foo(A*)"; 90 | } 91 | 92 | fn foo(_: B*) : string { 93 | return "D.foo(B*)"; 94 | } 95 | 96 | fn foo(_: int*) : string { 97 | return "D.foo(int*)"; 98 | } 99 | 100 | fn foo(_: int[10]) : string { 101 | return "D.foo(int[10])"; 102 | } 103 | 104 | fn foo(_: int, _: int) : string { 105 | return "D.foo(int, int)"; 106 | } 107 | 108 | fn foo(_: A*, _: void*) : string { 109 | return "D.foo(A*, void*)"; 110 | } 111 | 112 | fn foo(_: B*, _: C*) : string { 113 | return "D.foo(B*, C*)"; 114 | } 115 | 116 | fn foo(_: A*, _: C*) : string { 117 | return "D.foo(A*, C*)"; 118 | } 119 | 120 | fn foo(_: void*, _: void*) : string { 121 | return "D.foo(void*, void*)"; 122 | } 123 | 124 | fn foo(_: string, _: string) : string { 125 | return "D.foo(string, string)"; 126 | } 127 | 128 | fn foo(_: string, _: char*) : string { 129 | return "D.foo(string, char*)"; 130 | } 131 | } 132 | 133 | fn foo(_: void*) : string { 134 | return "foo(void*)"; 135 | } 136 | 137 | fn foo(_: A*) : string { 138 | return "foo(A*)"; 139 | } 140 | 141 | fn foo(_: B*) : string { 142 | return "foo(B*)"; 143 | } 144 | 145 | fn foo(_: int*) : string { 146 | return "foo(int*)"; 147 | } 148 | 149 | fn foo(_: int[10]) : string { 150 | return "foo(int[10])"; 151 | } 152 | 153 | fn foo(_: int, _: int) : string { 154 | return "foo(int, int)"; 155 | } 156 | 157 | fn foo(_: A*, _: void*) : string { 158 | return "foo(A*, void*)"; 159 | } 160 | 161 | fn foo(_: B*, _: C*) : string { 162 | return "foo(B*, C*)"; 163 | } 164 | 165 | fn foo(_: A*, _: C*) : string { 166 | return "foo(A*, C*)"; 167 | } 168 | 169 | fn foo(_: void*, _: void*) : string { 170 | return "foo(void*, void*)"; 171 | } 172 | 173 | fn foo(_: string, _: string) : string { 174 | return "foo(string, string)"; 175 | } 176 | 177 | fn foo(_: string, _: char*) : string { 178 | return "foo(string, char*)"; 179 | } 180 | 181 | fn main() : float { 182 | { 183 | printLn("function overloading tests"); 184 | check("foo()", foo(), "foo()"); 185 | check("foo(10)", foo(10), "foo(int)"); 186 | check("foo(11.0)", foo(11.0), "foo(float)"); 187 | check("foo(""Hello"")", foo("Hello"), "foo(string)"); 188 | 189 | let p: char*; 190 | let sa: char[10]; 191 | 192 | check("foo(p)", foo(p), "foo(string)"); 193 | check("foo(sa)", foo(sa), "foo(string)"); 194 | 195 | let pa: A*; 196 | let pb: B*; 197 | let pc: C*; 198 | let pd: D*; 199 | 200 | check("foo(pa)", foo(pa), "foo(A*)"); 201 | check("foo(pb)", foo(pb), "foo(B*)"); 202 | check("foo(pc)", foo(pc), "foo(B*)"); 203 | check("foo(pd)", foo(pd), "foo(void*)"); 204 | 205 | let pi: int*; 206 | let ai: int[10]; 207 | let ai2: int[20]; 208 | 209 | check("foo(pi)", foo(pi), "foo(int*)"); 210 | check("foo(ai)", foo(ai), "foo(int[10])"); 211 | check("foo(ai2)", foo(ai2), "foo(int*)"); 212 | 213 | let pf: float*; 214 | let af: float[10]; 215 | 216 | check("foo(pf)", foo(pf), "foo(void*)"); 217 | check("foo(af)", foo(af), "foo(void*)"); 218 | 219 | check("foo(10, 20)", foo(10, 20), "foo(int, int)"); 220 | check("foo(pa, pb)", foo(pa, pb), "foo(A*, void*)"); 221 | check("foo(pa, pc)", foo(pa, pc), "foo(A*, C*)"); 222 | check("foo(pb, pc)", foo(pb, pc), "foo(B*, C*)"); 223 | check("foo(pc, pc)", foo(pc, pc), "foo(B*, C*)"); 224 | 225 | let pe: E*; 226 | 227 | check("foo(pf, pa)", foo(pf, pa), "foo(void*, void*)"); 228 | check("foo(pe, pb)", foo(pe, pb), "foo(A*, void*)"); 229 | check("foo(""Hello"", p)", foo("Hello", p), "foo(string, char*)"); 230 | check("foo(sa, p)", foo(sa, p), "foo(string, char*)"); 231 | } 232 | 233 | { 234 | let d: D; 235 | 236 | printLn("class member overloading tests"); 237 | check("d.foo()", d.foo(), "D.foo()"); 238 | check("d.foo(10)", d.foo(10), "D.foo(int)"); 239 | check("d.foo(11.0)", d.foo(11.0), "D.foo(float)"); 240 | check("d.foo(""Hello"")", d.foo("Hello"), "D.foo(string)"); 241 | 242 | let p: char*; 243 | let sa: char[10]; 244 | 245 | check("d.foo(p)", d.foo(p), "D.foo(string)"); 246 | check("d.foo(sa)", d.foo(sa), "D.foo(string)"); 247 | 248 | let pa: A*; 249 | let pb: B*; 250 | let pc: C*; 251 | let pd: D*; 252 | 253 | check("d.foo(pa)", d.foo(pa), "D.foo(A*)"); 254 | check("d.foo(pb)", d.foo(pb), "D.foo(B*)"); 255 | check("d.foo(pc)", d.foo(pc), "D.foo(B*)"); 256 | check("d.foo(pd)", d.foo(pd), "D.foo(void*)"); 257 | 258 | let pi: int*; 259 | let ai: int[10]; 260 | let ai2: int[20]; 261 | 262 | check("d.foo(pi)", d.foo(pi), "D.foo(int*)"); 263 | check("d.foo(ai)", d.foo(ai), "D.foo(int[10])"); 264 | check("d.foo(ai2)", d.foo(ai2), "D.foo(int*)"); 265 | 266 | let pf: float*; 267 | let af: float[10]; 268 | 269 | check("d.foo(pf)", d.foo(pf), "D.foo(void*)"); 270 | check("d.foo(af)", d.foo(af), "D.foo(void*)"); 271 | 272 | check("d.foo(10, 20)", d.foo(10, 20), "D.foo(int, int)"); 273 | check("d.foo(pa, pb)", d.foo(pa, pb), "D.foo(A*, void*)"); 274 | check("d.foo(pa, pc)", d.foo(pa, pc), "D.foo(A*, C*)"); 275 | check("d.foo(pb, pc)", d.foo(pb, pc), "D.foo(B*, C*)"); 276 | check("d.foo(pc, pc)", d.foo(pc, pc), "D.foo(B*, C*)"); 277 | 278 | let pe: E*; 279 | 280 | check("d.foo(pf, pa)", d.foo(pf, pa), "D.foo(void*, void*)"); 281 | check("d.foo(pe, pb)", d.foo(pe, pb), "D.foo(A*, void*)"); 282 | check("d.foo(""Hello"", p)", d.foo("Hello", p), "D.foo(string, char*)"); 283 | check("d.foo(sa, p)", d.foo(sa, p), "D.foo(string, char*)"); 284 | } 285 | 286 | return 0.0; 287 | } -------------------------------------------------------------------------------- /include/simple/Basic/Diagnostic.def: -------------------------------------------------------------------------------- 1 | #ifndef DIAG 2 | #define DIAG(ID, Level, Msg) 3 | #endif 4 | 5 | DIAG(ERR_UnterminatedBlockComment, Error, "unterminated /* comment") 6 | DIAG(ERR_FloatingPointNoDigitsInExponent, Error, "missing digits in exponent") 7 | DIAG(ERR_UnterminatedCharOrString, Error, "missing terminating character") 8 | DIAG(ERR_NewLineInString, Error, "new line in string") 9 | DIAG(ERR_InvalidCharacter, Error, "invalid character") 10 | DIAG(ERR_InvalidEscapeSequence, Error, "invalid escape sequence") 11 | 12 | DIAG(ERR_Expected, Error, "expected {0} but found {1}") 13 | DIAG(ERR_ExpectedExpression, Error, "expected expression") 14 | DIAG(ERR_DynArrayAggregate, Error, "aggregate not allowed in dynamic arrays") 15 | DIAG(ERR_ExpectedExpressionAfterQuestion, Error, "expected expression after ?") 16 | DIAG(ERR_InvalidType, Error, "invalid type") 17 | DIAG(ERR_VoidAsNonPointer, Error, "'void' can be used only as pointer") 18 | DIAG(ERR_ExpectedFuncBody, Error, "expected function body") 19 | DIAG(ERR_VirtOverAsNonClassMember, Error, "'virt' or 'impl' can be used only in classes") 20 | DIAG(ERR_UnexpectedDestructorDecl, Error, "destructor can only be declared in classes") 21 | DIAG(ERR_ExpectedDestructorBody, Error, "expected destructor body") 22 | DIAG(ERR_UnexpectedConstructorDecl, Error, "consturctor can only be declared in classes") 23 | DIAG(ERR_ExpectedConstructorBody, Error, "expected constuctor body") 24 | DIAG(ERR_ExpectedSuperAfterNew, Error, "expected 'super' after 'new'") 25 | DIAG(ERR_ExpectedFuncArguments, Error, "expected arguments for function call") 26 | DIAG(ERR_ExpectedQualifiedNameAsBase, Error, "expected qualified identifier as base class") 27 | DIAG(ERR_ExpectedEndOfFile, Error, "expected end of file") 28 | DIAG(ERR_ExpectedIdentifierInDecl, Error, "expected identifier in declaration") 29 | DIAG(ERR_AggregateOrArrayInitializer, Error, "arrays or aggrgates can't have initializers") 30 | DIAG(ERR_InvalidStatement, Error, "invalid statement") 31 | 32 | DIAG(ERR_SemaIdentifierRedefinition, Error, "redefinition of identifier") 33 | DIAG(ERR_SemaUndefinedIdentifier, Error, "undefined identifier {0}") 34 | DIAG(ERR_SemaUndefinedMember, Error, "undefined member {0}") 35 | DIAG(ERR_SemaArrayOfClassUnsupported, Error, "array of classes unsupported") 36 | DIAG(ERR_SemaArrayOrAggregateAsReturnType, Error, "can't use aggregate/array as function's return value (use pointer instead)") 37 | DIAG(ERR_SemaAggregateAsFunctionParameter, Error, "can't use aggregate as function's parameter (use pointer instead)") 38 | DIAG(ERR_SemaClassAsStructMember, Error, "can't use class as structure's member (use pointer instead)") 39 | DIAG(ERR_SemaCantConvertToBoolean, Error, "can't convert to bool") 40 | DIAG(ERR_SemaCricularReference, Error, "circular reference in struct {0}") 41 | DIAG(ERR_SemaBaseClassNoConstructorToCall, Error, "base class doesn't have constructors to call") 42 | DIAG(ERR_SemaVirtualFunctionReturnTypeOverload, Error, "function {0} in {1} has different return type") 43 | DIAG(ERR_SemaConstructionCallInStruct, Error, "constructor call for structure used") 44 | DIAG(ERR_SemaPointerInitialization, Error, "pointer should have pointer type initializer or 0") 45 | DIAG(ERR_SemaVoidInitializer, Error, "initialization from void value") 46 | DIAG(ERR_SemaInvalidBaseClass, Error, "only class/struct can be used as base class") 47 | DIAG(ERR_SemaVirtualFunctionExists, Error, "function already exist in the VTable. use impl instead") 48 | DIAG(ERR_SemaOverrideFunctionDoesntExists, Error, "impl function should exist in the VTable. use virtual instead") 49 | DIAG(ERR_SemaMainParameters, Error, "main should have 0 parameters") 50 | DIAG(ERR_SemaMainReturnType, Error, "main should have float return type") 51 | DIAG(ERR_SemaFunctionRedefined, Error, "function redefined {0}") 52 | DIAG(ERR_SemaMissingReturnValueInFunction, Error, "function should has return value") 53 | DIAG(ERR_SemaDuplicateFunctions, Error, "overload already used for function {0}") 54 | DIAG(ERR_SemaNoTypeForExpression, Error, "expression should have type") 55 | DIAG(ERR_SemaDeadCode, Error, "code can't be reached because of jump statement") 56 | DIAG(ERR_SemaInvalidJumpStatement, Error, "jump statement can be only in the loop") 57 | DIAG(ERR_SemaReturnValueInVoidFunction, Error, "void function has return value") 58 | DIAG(ERR_SemaReturnVoidFromFunction, Error, "non void function has no return value") 59 | DIAG(ERR_SemaConditionIsVoid, Error, "condition is void") 60 | DIAG(ERR_SemaPointerArithmeticsForNonInt, Error, "pointer arithmetic only allowed pointer and int operands") 61 | DIAG(ERR_SemaCantDeleteVoid, Error, "can't delete void value") 62 | DIAG(ERR_SemaCantDeleteNonPointer, Error, "can't delete non pointer value") 63 | DIAG(ERR_SemaNonAggregateDotOperand, Error, "missing class/struct as left part of . expression") 64 | DIAG(ERR_SemaNonIndexableType, Error, "indexing used for non array/pointer") 65 | DIAG(ERR_SemaNonAggregateForFocedThis, Error, "missing class/struct for forced this") 66 | DIAG(ERR_SemaInvalidPostfixPrefixOperand, Error, "invalid operand for ++/-- (should be identifier)") 67 | DIAG(ERR_SemaOperandIsVoid, Error, "operand is void") 68 | DIAG(ERR_SemaAmbiguousCall, Error, "ambiguous call") 69 | DIAG(ERR_SemaUnDereferencableType, Error, "value of dereference operation should have pointer type") 70 | DIAG(ERR_SemaAggregateAsExpression, Error, "class/struct used as expression") 71 | DIAG(ERR_SemaInvalidOperandForMemberAccess, Error, "invalid expression in member access") 72 | DIAG(ERR_SemaNonLValueForMemberAccess, Error, "missing lvalue as left part of . expression") 73 | DIAG(ERR_SemaMemberAccessOnAggregateType, Error, "member access used on class/struct name") 74 | DIAG(ERR_SemaAggregateTypeAsMemberAccessOperand, Error, "result of member access should be variable/function not aggregate") 75 | DIAG(ERR_SemaCastToVoid, Error, "void used in cast expression") 76 | DIAG(ERR_SemaInvalidCast, Error, "invalid conversion") 77 | DIAG(ERR_SemaFunctionInCast, Error, "function used in cast expression") 78 | DIAG(ERR_SemaArrayInCast, Error, "array used in cast expression") 79 | DIAG(ERR_SemaIncompatiblePointerTypes, Error, "incompatible pointer types") 80 | DIAG(ERR_SemaConstStringDeRef, Error, "can't dereference constant string") 81 | DIAG(ERR_SemaAddressExpressionNoType, Error, "address expression should have type") 82 | DIAG(ERR_SemaAddressOfNonLValue, Error, "operand of & should be lvalue") 83 | DIAG(ERR_SemaInvalidUnaryExpressionForString, Error, "string only allowed in ++/-- unary expressions") 84 | DIAG(ERR_SemaInvalidUnaryExpressionForArray, Error, "array used in unary expression") 85 | DIAG(ERR_SemaInvalidUnaryExpressionForPointer, Error, "pointers only allowed in ++/-- unary expressions") 86 | DIAG(ERR_SemaInvalidBoolForUnaryOperands, Error, "+/- can't have boolean operand") 87 | DIAG(ERR_SemaInvalidOperandForComplemet, Error, "invalid type for ~ expression operand") 88 | DIAG(ERR_SemaUntypedBinaryExpressionOperands, Error, "left/right operands of binary expression should have types") 89 | DIAG(ERR_SemaInvalidTypeForComparison, Error, "invalid type for comparison expression") 90 | DIAG(ERR_SemaMissingLValueInAssignment, Error, "left side of = should be lvalue") 91 | DIAG(ERR_SemaCantUseArrayInBinaryExpression, Error, "can't use array in binary expression") 92 | DIAG(ERR_SemaPointerOrStringInBinaryExpression, Error, "pointer or string can be used only in = or +/- binary expressions") 93 | DIAG(ERR_SemaInvalidBinaryExpressionForFloatingPoint, Error, "invalid floating point binary operator") 94 | DIAG(ERR_SemaInvalidNumberOfArgumentsInCall, Error, "invalid number of arguments") 95 | DIAG(ERR_SemaInvalidTypesOfArgumentsInCall, Error, "invalid argument for function's call") 96 | DIAG(ERR_SemaInvalidArgumentsForCall, Error, "invalid argument for function's call") 97 | 98 | #undef DIAG -------------------------------------------------------------------------------- /lib/Lexer/Lexer.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/Lexer/Lexer.h" 2 | 3 | namespace simple { 4 | 5 | Name *NamesMap::addName(StringRef Id, tok::TokenKind TokenCode) { 6 | auto newKey = HashTable.insert(std::make_pair(Id, Name())); 7 | 8 | if (!newKey.second) { 9 | return &newKey.first->getValue(); 10 | } 11 | 12 | Name *name = &newKey.first->getValue(); 13 | 14 | name->Id = newKey.first->getKeyData(); 15 | name->Length = Id.size(); 16 | name->Kind = TokenCode; 17 | 18 | return name; 19 | } 20 | 21 | void NamesMap::addKeywords() { 22 | if (IsInit) { 23 | return; 24 | } 25 | 26 | #define KEYWORD(NAME, TEXT) \ 27 | addName(StringRef(TEXT), tok::NAME); 28 | #include "simple/Basic/TokenKinds.def" 29 | 30 | Name::This = getName("this"); 31 | Name::Super = getName("super"); 32 | Name::New = getName("new"); 33 | Name::Delete = getName("delete"); 34 | Name::Ctor = addName("__ctor", tok::Identifier); 35 | Name::Dtor = addName("__dtor", tok::Identifier); 36 | 37 | IsInit = true; 38 | } 39 | 40 | Name *NamesMap::getName(StringRef Id) { 41 | return addName(Id, tok::Identifier); 42 | } 43 | 44 | namespace charinfo { 45 | LLVM_READNONE inline bool isASCII(char Ch) { 46 | return static_cast(Ch) <= 127; 47 | } 48 | 49 | LLVM_READNONE inline bool isVerticalWhitespace(char Ch) { 50 | return isASCII(Ch) && (Ch == '\r' || Ch == '\n'); 51 | } 52 | 53 | LLVM_READNONE inline bool isHorizontalWhitespace(char Ch) { 54 | return isASCII(Ch) && (Ch == ' ' || Ch == '\t' || Ch == '\f' || Ch == '\v'); 55 | } 56 | 57 | LLVM_READNONE inline bool isWhitespace(char Ch) { 58 | return isHorizontalWhitespace(Ch) || isVerticalWhitespace(Ch); 59 | } 60 | 61 | LLVM_READNONE inline bool isDigit(char Ch) { 62 | return isASCII(Ch) && Ch >= '0' && Ch <= '9'; 63 | } 64 | 65 | LLVM_READNONE inline bool isIdentifierHead(char Ch) { 66 | return isASCII(Ch) && 67 | (Ch == '_' || (Ch >= 'A' && Ch <= 'Z') || (Ch >= 'a' && Ch <= 'z')); 68 | } 69 | 70 | LLVM_READNONE inline bool isIdentifierBody(char Ch) { 71 | return isIdentifierHead(Ch) || isDigit(Ch); 72 | } 73 | } 74 | 75 | NamesMap Lexer::IdsMap; 76 | 77 | void Lexer::next(Token &Result) { 78 | // Set token to invalid state 79 | Result.Kind = tok::Invalid; 80 | 81 | // We should change original read position only when token is fully read 82 | const char *p = CurPos; 83 | 84 | // Read all tokens in the loop until we find a valid token 85 | while (Result.Kind == tok::Invalid) { 86 | const char *tokenStart = p; 87 | 88 | #define CHECK_ONE(CHR, TOK) \ 89 | case CHR: \ 90 | Result.Length = 1; \ 91 | Result.Kind = TOK; \ 92 | break 93 | 94 | #define CHECK_TWO(CH1, CH2, T1, T2) \ 95 | case CH1: \ 96 | if (*p == CH2) { \ 97 | ++p; \ 98 | Result.Length = 2; \ 99 | Result.Kind = T1; \ 100 | } else { \ 101 | Result.Length = 1; \ 102 | Result.Kind = T2; \ 103 | } \ 104 | break 105 | 106 | switch (char ch = *p++) { 107 | case 0: 108 | // It's end of file. Backtrack to '\0' (we can reread it again) 109 | --p; 110 | Result.Kind = tok::EndOfFile; 111 | break; 112 | 113 | case '\n': 114 | case '\r': 115 | case ' ': 116 | case '\t': 117 | case '\v': 118 | case '\f': 119 | // Skip all whitespaces 120 | while (charinfo::isWhitespace(*p)) { 121 | ++p; 122 | } 123 | // Read next token 124 | continue; 125 | 126 | 127 | CHECK_ONE('~', tok::Tilda); 128 | CHECK_ONE('*', tok::Mul); 129 | CHECK_ONE('%', tok::Mod); 130 | CHECK_ONE('^', tok::BitXor); 131 | CHECK_ONE(',', tok::Comma); 132 | CHECK_ONE('?', tok::Question); 133 | CHECK_ONE(':', tok::Colon); 134 | CHECK_ONE(';', tok::Semicolon); 135 | CHECK_ONE('(', tok::OpenParen); 136 | CHECK_ONE(')', tok::CloseParen); 137 | CHECK_ONE('{', tok::BlockStart); 138 | CHECK_ONE('}', tok::BlockEnd); 139 | CHECK_ONE('[', tok::OpenBrace); 140 | CHECK_ONE(']', tok::CloseBrace); 141 | CHECK_ONE('.', tok::Dot); 142 | 143 | CHECK_TWO('-', '-', tok::MinusMinus, tok::Minus); 144 | CHECK_TWO('+', '+', tok::PlusPlus, tok::Plus); 145 | CHECK_TWO('!', '=', tok::NotEqual, tok::Not); 146 | CHECK_TWO('=', '=', tok::Equal, tok::Assign); 147 | CHECK_TWO('|', '|', tok::LogOr, tok::BitOr); 148 | CHECK_TWO('&', '&', tok::LogAnd, tok::BitAnd); 149 | 150 | case '/': 151 | if (*p == '/') { 152 | ++p; 153 | 154 | while (*p && (*p != '\r' && *p != '\n')) { 155 | ++p; 156 | } 157 | break; 158 | } else if (*p == '*') { 159 | unsigned Level = 1; 160 | ++p; 161 | 162 | while (*p && Level) { 163 | // Check for nested comment 164 | if (*p == '/' && p[1] == '*') { 165 | p += 2; 166 | ++Level; 167 | // Check for end of comment 168 | } else if (*p == '*' && p[1] == '/' && Level) { 169 | p += 2; 170 | --Level; 171 | } else { 172 | ++p; 173 | } 174 | } 175 | 176 | if (Level) { 177 | Diags.report(getLoc(p), diag::ERR_UnterminatedBlockComment); 178 | } 179 | 180 | continue; 181 | } else { 182 | Result.Length = 1; 183 | Result.Kind = tok::Div; 184 | break; 185 | } 186 | 187 | case '<': 188 | if (*p == '=') { 189 | ++p; 190 | Result.Length = 2; 191 | Result.Kind = tok::LessEqual; 192 | break; 193 | } else if (*p == '<') { 194 | ++p; 195 | Result.Length = 2; 196 | Result.Kind = tok::LShift; 197 | break; 198 | } else { 199 | Result.Length = 1; 200 | Result.Kind = tok::Less; 201 | break; 202 | } 203 | 204 | case '>': 205 | if (*p == '=') { 206 | ++p; 207 | Result.Length = 2; 208 | Result.Kind = tok::GreaterEqual; 209 | break; 210 | } else if (*p == '>') { 211 | ++p; 212 | Result.Length = 2; 213 | Result.Kind = tok::RShift; 214 | break; 215 | } else { 216 | Result.Length = 1; 217 | Result.Kind = tok::Greater; 218 | break; 219 | } 220 | 221 | case '1': 222 | case '2': 223 | case '3': 224 | case '4': 225 | case '5': 226 | case '6': 227 | case '7': 228 | case '8': 229 | case '9': 230 | while (charinfo::isDigit(*p)) { 231 | ++p; 232 | } 233 | 234 | case '0': 235 | Result.Kind = tok::IntNumber; 236 | 237 | if (*p == '.') { 238 | // Keep 1st digit after . 239 | const char *firstDigit = p++; 240 | 241 | while (charinfo::isDigit(*p)) { 242 | ++p; 243 | } 244 | 245 | // Check for exponent 246 | if (*p == 'e' || *p == 'E') { 247 | ++p; 248 | 249 | if (*p == '+' || *p == '-') { 250 | ++p; 251 | } 252 | 253 | // Keep 1st digit after [eE][+-]? 254 | firstDigit = p; 255 | 256 | while (charinfo::isDigit(*p)) { 257 | ++p; 258 | } 259 | 260 | // We should have at least 1 digit in the exponent part 261 | if (p == firstDigit) { 262 | Diags.report(getLoc(p), diag::ERR_FloatingPointNoDigitsInExponent); 263 | } 264 | } 265 | 266 | Result.Kind = tok::FloatNumber; 267 | } 268 | 269 | // Copy literal content in the token 270 | Result.Length = (int)(p - tokenStart); 271 | Result.Literal = new char[Result.Length + 1]; 272 | memcpy(Result.Literal, tokenStart, Result.Length); 273 | Result.Literal[Result.Length] = 0; 274 | break; 275 | 276 | case '\'': { 277 | char resultCh = ' '; 278 | 279 | if (*p != '\'') { 280 | resultCh = *p; 281 | ++p; 282 | } 283 | 284 | if (*p != '\'') { 285 | Diags.report(getLoc(p), diag::ERR_UnterminatedCharOrString); 286 | } 287 | 288 | ++p; 289 | 290 | Result.Length = (int)(p - tokenStart); 291 | Result.Chr = resultCh; 292 | Result.Kind = tok::CharLiteral; 293 | break; 294 | } 295 | 296 | case '"': { 297 | llvm::SmallString<32> str; 298 | 299 | while (*p) { 300 | if (*p == '"') { 301 | // If it's " then we are done 302 | if (p[1] != '"') { 303 | break; 304 | } 305 | 306 | // It's "" replace it with " 307 | p += 2; 308 | str.push_back('"'); 309 | } else if (*p == '\\') { 310 | ++p; 311 | // We only allow \\ and \n 312 | if (*p == 'n') { 313 | str.push_back('\n'); 314 | ++p; 315 | } else if (*p == '\\') { 316 | str.push_back('\\'); 317 | ++p; 318 | } else { 319 | Diags.report(getLoc(p), diag::ERR_InvalidEscapeSequence); 320 | } 321 | } else if (*p == '\r' || *p == '\n') { 322 | Diags.report(getLoc(p), diag::ERR_NewLineInString); 323 | } else { 324 | str.push_back(*p); 325 | ++p; 326 | } 327 | } 328 | 329 | if (*p != '"') { 330 | Diags.report(getLoc(p), diag::ERR_UnterminatedCharOrString); 331 | } 332 | 333 | ++p; 334 | 335 | Result.Kind = tok::StringConstant; 336 | Result.Length = str.size(); 337 | Result.Literal = new char[Result.Length + 1]; 338 | memcpy(Result.Literal, str.c_str(), Result.Length); 339 | Result.Literal[Result.Length] = 0; 340 | break; 341 | } 342 | 343 | default: 344 | // Check for identifier 345 | if (charinfo::isIdentifierHead(ch)) { 346 | // Read full identifier 347 | while (charinfo::isIdentifierBody(*p)) { 348 | ++p; 349 | } 350 | 351 | size_t length = (size_t)(p - tokenStart); 352 | Name *name = IdsMap.getName(StringRef(tokenStart, length)); 353 | 354 | Result.Id = name; 355 | Result.Kind = (tok::TokenKind)name->Kind; 356 | Result.Length = name->Length; 357 | 358 | break; 359 | } else { 360 | Diags.report(getLoc(p), diag::ERR_InvalidCharacter); 361 | break; 362 | } 363 | } 364 | 365 | Result.Ptr = tokenStart; 366 | } 367 | 368 | // Update current read position 369 | CurPos = p; 370 | } 371 | 372 | } // namespace simple -------------------------------------------------------------------------------- /lib/Sema/Types.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/AST/AST.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace simple { 6 | 7 | // TypeAST implementation 8 | StringSet< > TypeAST::TypesTable; 9 | static std::vector< TypeAST* > TypesToDelete; 10 | 11 | void TypeAST::registerTypeForDeletion(TypeAST* thisType) { 12 | TypesToDelete.push_back(thisType); 13 | } 14 | 15 | void TypeAST::clearAllTypes() { 16 | for (std::vector< TypeAST* >::iterator it = TypesToDelete.begin(), 17 | end = TypesToDelete.end(); it != end; ++it) { 18 | delete *it; 19 | } 20 | 21 | TypesToDelete.clear(); 22 | } 23 | 24 | void TypeAST::calcMangle() { 25 | if (!MangleName.empty()) { 26 | return; 27 | } 28 | 29 | // 128 bytes is enough for most types 30 | llvm::SmallString< 128 > s; 31 | llvm::raw_svector_ostream output(s); 32 | 33 | // Write mangle name for type into buffer and add it to the types table 34 | toMangleBuffer(output); 35 | 36 | TypesTable.insert(output.str()); 37 | 38 | // Get just added value from table and set MangleName from this value 39 | StringSet< >::iterator pos = TypesTable.find(s); 40 | assert(pos != TypesTable.end()); 41 | MangleName = pos->getKeyData(); 42 | } 43 | 44 | bool TypeAST::isBaseOf(TypeAST* ) { 45 | return false; 46 | } 47 | 48 | bool TypeAST::equal(TypeAST* otherType) { 49 | // equal only valid if 2 types have MangleName 50 | // note: We check types equivalence by their mangle name and not their 51 | // content, because it's much cheaper and give same result 52 | assert(!MangleName.empty() && !otherType->MangleName.empty()); 53 | return MangleName == otherType->MangleName; 54 | } 55 | 56 | SymbolAST* TypeAST::getSymbol() { 57 | return nullptr; 58 | } 59 | 60 | TypeAST* BuiltinTypeAST::semantic(Scope* scope) { 61 | calcMangle(); 62 | return this; 63 | } 64 | 65 | // BuiltinTypeAST implementation 66 | TypeAST *BuiltinTypeAST::get(int type) { 67 | static TypeAST *builtinTypes[] = { 68 | new BuiltinTypeAST(TI_Void), 69 | new BuiltinTypeAST(TI_Bool), 70 | new BuiltinTypeAST(TI_Int), 71 | new BuiltinTypeAST(TI_Float), 72 | new BuiltinTypeAST(TI_Char), 73 | new BuiltinTypeAST(TI_String) 74 | }; 75 | 76 | assert(type >= TI_Void && type <= TI_String); 77 | return builtinTypes[type]; 78 | } 79 | 80 | bool BuiltinTypeAST::implicitConvertTo(TypeAST* newType) { 81 | static bool convertResults[TI_String + 1][TI_String + 1] = { 82 | // void bool int float char string 83 | { false, false, false, false, false, false }, // void 84 | { false, true, true, true, true, false }, // bool 85 | { false, true, true, true, true, false }, // int 86 | { false, true, true, true, false, false }, // float 87 | { false, true, true, true, true, false }, // char 88 | { false, true, false, false, false, true } // string 89 | }; 90 | 91 | if (newType->TypeKind > TI_String) { 92 | return false; 93 | } 94 | 95 | return convertResults[TypeKind][newType->TypeKind]; 96 | } 97 | 98 | void BuiltinTypeAST::toMangleBuffer(llvm::raw_ostream& output) { 99 | switch (TypeKind) { 100 | case TI_Void : output << "v"; break; 101 | case TI_Bool : output << "b"; break; 102 | case TI_Int : output << "i"; break; 103 | case TI_Float : output << "f"; break; 104 | case TI_Char : output << "c"; break; 105 | case TI_String : output << "PKc"; break; 106 | default: assert(0 && "Should never happen"); break; 107 | } 108 | } 109 | 110 | // ArrayTypeAST implementation 111 | TypeAST* ArrayTypeAST::semantic(Scope* scope) { 112 | // Check semantic of inner type 113 | Next = Next->semantic(scope); 114 | 115 | // Disable array of class 116 | if (isa(Next)) { 117 | scope->report(SMLoc(), diag::ERR_SemaArrayOfClassUnsupported); 118 | return nullptr; 119 | } 120 | 121 | // Calculate MangleName 122 | calcMangle(); 123 | return this; 124 | } 125 | 126 | bool ArrayTypeAST::implicitConvertTo(TypeAST* newType) { 127 | TypeAST* next1 = Next; 128 | TypeAST* next2 = nullptr; 129 | 130 | // char[] can be converted to string 131 | if (Next->isChar() && newType->isString()) { 132 | return true; 133 | } 134 | 135 | // If it's not type[] or type* then. We can't convert types 136 | if (!(isa(newType) || isa(newType))) { 137 | return false; 138 | } 139 | 140 | // Get inner type from pointer/array 141 | if (isa(newType)) { 142 | next2 = ((PointerTypeAST*)newType)->Next; 143 | } else if (isa(newType)) { 144 | ArrayTypeAST* arrayType = (ArrayTypeAST*)newType; 145 | 146 | // If it's array then dimensions should be equal too 147 | if (arrayType->Dim != Dim) { 148 | return false; 149 | } 150 | 151 | next2 = arrayType->Next; 152 | } 153 | 154 | // We allow any array to void* conversion 155 | if (next2->isVoid()) { 156 | return true; 157 | } 158 | 159 | // We allow only top level type[] to type* conversion 160 | return next1->equal(next2); 161 | } 162 | 163 | void ArrayTypeAST::toMangleBuffer(llvm::raw_ostream& output) { 164 | output << "A" << Dim << "_"; 165 | Next->toMangleBuffer(output); 166 | } 167 | 168 | // PointerTypeAST implementation 169 | TypeAST* PointerTypeAST::semantic(Scope* scope) { 170 | // Check semantic on inner type and calculate MangleName 171 | Next = Next->semantic(scope); 172 | calcMangle(); 173 | return this; 174 | } 175 | 176 | bool PointerTypeAST::implicitConvertTo(TypeAST* newType) { 177 | // We can convert pointer to boolean 178 | if (newType->isBool()) { 179 | return true; 180 | } 181 | 182 | // char* can be converted to string 183 | if (Next->isChar() && newType->isString()) { 184 | return true; 185 | } 186 | 187 | // We disable any conversions from pointer to non pointer 188 | if (!isa(newType)) { 189 | return false; 190 | } 191 | 192 | PointerTypeAST* ptr2 = (PointerTypeAST*)newType; 193 | // Get inner type for newType 194 | TypeAST* next2 = ptr2->Next; 195 | 196 | // Check are inner types equal or not 197 | if (Next->equal(next2)) { 198 | return true; 199 | } 200 | 201 | // If inner types are aggregates then we should check is next2 base of 202 | // Next or not. 203 | // Note: Only 1 level of nested pointers are allowed for aggregates 204 | if (Next->isAggregate() && next2->isAggregate()) { 205 | return next2->isBaseOf(Next); 206 | } 207 | 208 | TypeAST* next1 = Next; 209 | 210 | // We allow conversion of any type* to void* 211 | if (next2->isVoid()) { 212 | return true; 213 | } 214 | 215 | return false; 216 | } 217 | 218 | void PointerTypeAST::toMangleBuffer(llvm::raw_ostream& output) { 219 | output << "P"; 220 | Next->toMangleBuffer(output); 221 | } 222 | 223 | // StructTypeAST implementation 224 | /// Calculate mangle name for aggregate 225 | /// \param[in] output - output buffer 226 | /// \param[in] thisSym - aggregate which mangle name we should get 227 | void mangleAggregateName(llvm::raw_ostream& output, SymbolAST* thisSym) { 228 | assert(thisSym && thisSym->isAggregate()); 229 | SymbolAST* sym = thisSym; 230 | 231 | output << "N"; 232 | 233 | // We create N Length Name E for aggregate or N Length1 Name1 Length2 Name2 E 234 | // for nested aggregates. 235 | // example: 236 | // A::B::C will be N1A1B1CE 237 | // A will be N1AE 238 | 239 | for ( ; ; ) { 240 | if (!sym || !sym->isAggregate()) { 241 | output << "E"; 242 | return; 243 | } 244 | 245 | output << sym->Id->Length << StringRef(sym->Id->Id, sym->Id->Length); 246 | sym = sym->Parent; 247 | } 248 | } 249 | 250 | TypeAST* StructTypeAST::semantic(Scope* scope) { 251 | calcMangle(); 252 | return this; 253 | } 254 | 255 | 256 | bool StructTypeAST::implicitConvertTo(TypeAST* newType) { 257 | return false; 258 | } 259 | 260 | void StructTypeAST::toMangleBuffer(llvm::raw_ostream& output) { 261 | mangleAggregateName(output, ThisDecl); 262 | } 263 | 264 | bool StructTypeAST::isBaseOf(TypeAST* type) { 265 | // if type isn't class then this can't be it's base 266 | if (!isa(type)) { 267 | return false; 268 | } 269 | 270 | ClassTypeAST* classType = (ClassTypeAST*)type; 271 | ClassDeclAST* classDecl = (ClassDeclAST*)classType->ThisDecl; 272 | 273 | // If this and base class of type are same then we are done 274 | if (classDecl->BaseClass && this->equal(classDecl->BaseClass)) { 275 | return true; 276 | } 277 | 278 | // Check is this base class of type's base class or not 279 | if (classDecl->BaseClass) { 280 | return isBaseOf(classDecl->BaseClass); 281 | } 282 | 283 | return false; 284 | } 285 | 286 | SymbolAST* StructTypeAST::getSymbol() { 287 | return ThisDecl; 288 | } 289 | 290 | // ClassTypeAST implementation 291 | TypeAST* ClassTypeAST::semantic(Scope* scope) { 292 | calcMangle(); 293 | return this; 294 | } 295 | 296 | bool ClassTypeAST::implicitConvertTo(TypeAST* newType) { 297 | if (newType->equal(this)) { 298 | return true; 299 | } 300 | 301 | return false; 302 | } 303 | 304 | void ClassTypeAST::toMangleBuffer(llvm::raw_ostream& output) { 305 | mangleAggregateName(output, ThisDecl); 306 | } 307 | 308 | bool ClassTypeAST::isBaseOf(TypeAST* type) { 309 | // if type isn't class then this can't be it's base 310 | if (!isa(type)) { 311 | return false; 312 | } 313 | 314 | ClassTypeAST* classType = (ClassTypeAST*)type; 315 | ClassDeclAST* classDecl = (ClassDeclAST*)classType->ThisDecl; 316 | 317 | // If this and base class of type are same then we are done 318 | if (classDecl->BaseClass && this->equal(classDecl->BaseClass)) { 319 | return true; 320 | } 321 | 322 | // Check is this base class of type's base class or not 323 | if (classDecl->BaseClass) { 324 | return isBaseOf(classDecl->BaseClass); 325 | } 326 | 327 | return false; 328 | } 329 | 330 | SymbolAST* ClassTypeAST::getSymbol() { 331 | return ThisDecl; 332 | } 333 | 334 | // FunctionTypeAST implementation 335 | TypeAST* FuncTypeAST::semantic(Scope* scope) { 336 | // We should run semantic for return type if it's exist 337 | if (!ReturnType) { 338 | ReturnType = BuiltinTypeAST::get(TypeAST::TI_Void); 339 | } 340 | 341 | ReturnType = ReturnType->semantic(scope); 342 | 343 | // Perform semantic on function parameters 344 | for (ParameterList::iterator it = Params.begin(), end = Params.end(); 345 | it != end; ++it) { 346 | (*it)->Param = (*it)->Param->semantic(scope); 347 | 348 | if ((*it)->Param->isAggregate()) { 349 | scope->report(SMLoc(), diag::ERR_SemaAggregateAsFunctionParameter); 350 | return nullptr; 351 | } 352 | } 353 | 354 | // We disallow arrays or aggregates as return type 355 | if (ReturnType && (ReturnType->isAggregate() || isa(ReturnType))) { 356 | scope->report(SMLoc(), diag::ERR_SemaArrayOrAggregateAsReturnType); 357 | return nullptr; 358 | } 359 | 360 | calcMangle(); 361 | return this; 362 | } 363 | 364 | bool FuncTypeAST::implicitConvertTo(TypeAST* newType) { 365 | return false; 366 | } 367 | 368 | void FuncTypeAST::toMangleBuffer(llvm::raw_ostream& output) { 369 | // Append v if function has 0 parameters 370 | if (Params.empty()) { 371 | output << "v"; 372 | return; 373 | } 374 | 375 | ParameterList::iterator it = Params.begin(), end = Params.end(); 376 | 377 | // Skip this parameter 378 | if (HasThis) { 379 | ++it; 380 | } 381 | 382 | // Append v if function has 0 parameters beside this 383 | if (it == end) { 384 | output << "v"; 385 | return; 386 | } 387 | 388 | // Write parameters' types to mangle buffer 389 | for ( ; it != end; ++it) { 390 | (*it)->Param->toMangleBuffer(output); 391 | } 392 | } 393 | 394 | // QualifiedTypeAST implementation 395 | TypeAST* QualifiedTypeAST::semantic(Scope* scope) { 396 | SymbolAST* sym = nullptr; 397 | 398 | // For every nested name we should resolve it in the scope 399 | for (QualifiedName::iterator it = QualName.begin(), end = QualName.end(); 400 | it != end; ++it) { 401 | 402 | if (sym) { 403 | // Now we should search as member of previously found symbol 404 | sym = sym->find((*it)); 405 | 406 | if (!sym) { 407 | scope->report(SMLoc(), diag::ERR_SemaUndefinedIdentifier, (*it)->Id); 408 | return nullptr; 409 | } 410 | } else { 411 | // It's 1st name and we should search it in the scope 412 | sym = scope->find((*it)); 413 | 414 | if (!sym) { 415 | scope->report(SMLoc(), diag::ERR_SemaUndefinedIdentifier, (*it)->Id); 416 | return nullptr; 417 | } 418 | } 419 | } 420 | 421 | return sym->getType(); 422 | } 423 | 424 | bool QualifiedTypeAST::implicitConvertTo(TypeAST* ) { 425 | assert(0 && "QualifiedTypeAST::implicitConvertTo should never be reached"); 426 | return false; 427 | } 428 | 429 | void QualifiedTypeAST::toMangleBuffer(llvm::raw_ostream& ) { 430 | assert(0 && "QualifiedTypeAST::toMangleBuffer should never be reached"); 431 | } 432 | 433 | } // namespace simple -------------------------------------------------------------------------------- /lib/Sema/Stmts.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/AST/AST.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace simple { 6 | 7 | // StmtAST hierarchy implementation 8 | // StmtAST implementation 9 | bool StmtAST::hasReturn() { 10 | return false; 11 | } 12 | 13 | bool StmtAST::hasJump() { 14 | return false; 15 | } 16 | 17 | StmtAST* StmtAST::semantic(Scope* scope) { 18 | if (SemaState > 0) { 19 | return this; 20 | } 21 | 22 | ++SemaState; 23 | return doSemantic(scope); 24 | } 25 | 26 | StmtAST* StmtAST::doSemantic(Scope* ) { 27 | assert(0 && "StmtAST::semantic should never be reached"); 28 | return this; 29 | } 30 | 31 | // ExprStmtAST implementation 32 | StmtAST* ExprStmtAST::doSemantic(Scope* scope) { 33 | if (Expr) { 34 | // Check semantic for an expression 35 | Expr = Expr->semantic(scope); 36 | 37 | // If expression has nullptr type then it's error 38 | if (!Expr->ExprType) { 39 | scope->report(Loc, diag::ERR_SemaNoTypeForExpression); 40 | return nullptr; 41 | } 42 | } 43 | 44 | return this; 45 | } 46 | 47 | /// Check does this block need to be promoted in new block or not 48 | /// \param[in] oldStmt - old statement 49 | /// \param[in] scope - current scope 50 | bool needPromoteBodyToBlock(StmtAST* oldStmt, Scope* scope) { 51 | // Only declarations can have new block 52 | if (!isa(oldStmt)) { 53 | return false; 54 | } 55 | 56 | // Perform semantic on this statement. We need to be sure that type is resolved 57 | // for variable 58 | DeclStmtAST* declStmt = (DeclStmtAST*)oldStmt->semantic(scope); 59 | SymbolList::iterator it = declStmt->Decls.begin(); 60 | assert(isa(*it)); 61 | VarDeclAST* var = (VarDeclAST*)*it; 62 | 63 | // Only class can lead to new block 64 | if (isa(var->ThisType)) { 65 | ClassDeclAST* classDecl = (ClassDeclAST*)var->ThisType->getSymbol(); 66 | 67 | // Only class with destructor can lead to new block 68 | if (classDecl->Dtor) { 69 | return true; 70 | } 71 | } 72 | 73 | return false; 74 | } 75 | 76 | // BlockStmtAST implementation 77 | bool BlockStmtAST::hasReturn() { 78 | return HasReturn; 79 | } 80 | 81 | bool BlockStmtAST::hasJump() { 82 | return HasJump; 83 | } 84 | 85 | StmtAST* BlockStmtAST::doSemantic(Scope* scope) { 86 | // For block statement we should create new scope 87 | ThisBlock = new ScopeSymbol(Loc, SymbolAST::SI_Block, nullptr); 88 | Scope* s = scope->push((ScopeSymbol*)ThisBlock); 89 | 90 | // Create landing pad 91 | // Note: We patch NeedCleanup later if needed 92 | LandingPad = new LandingPadAST(s->LandingPad, false); 93 | LandingPad->OwnerBlock = this; 94 | LandingPad->NeedCleanup = s->LandingPad->NeedCleanup; 95 | s->LandingPad = LandingPad; 96 | 97 | bool atStart = true; // We need that for new blocks creation 98 | ExprList args; 99 | 100 | // Check all nested statements 101 | for (StmtList::iterator it = Body.begin(), end = Body.end(); it != end; ++it) { 102 | // Jump statement should be last in a block 103 | if (HasJump) { 104 | scope->report(Loc, diag::ERR_SemaDeadCode); 105 | return nullptr; 106 | } 107 | 108 | if (needPromoteBodyToBlock(*it, s)) { 109 | // It's need cleanup 110 | LandingPad->NeedCleanup = true; 111 | 112 | if (!atStart) { 113 | // Append rest statements to new block 114 | StmtList body(it, end); 115 | BlockStmtAST* newBlockStmt = new BlockStmtAST(Loc, body); 116 | Body.erase(it, end); 117 | Body.push_back(newBlockStmt); 118 | // Perform semantic on just created block and get HasJump and HasReturn 119 | // from it 120 | newBlockStmt->IsPromoted = true; 121 | newBlockStmt->semantic(s); 122 | HasJump = newBlockStmt->HasJump; 123 | HasReturn = newBlockStmt->HasReturn; 124 | break; 125 | } 126 | 127 | DeclStmtAST* decls = (DeclStmtAST*)*it; 128 | 129 | for (SymbolList::iterator it2 = decls->Decls.begin(), end2 = decls->Decls.end(); 130 | it2 != end2; ++it2) { 131 | VarDeclAST* var = (VarDeclAST*)*it2; 132 | // Create destructor call for this variable 133 | ExprAST* cleanupExpr = new CallExprAST( 134 | Loc, 135 | new MemberAccessExprAST( 136 | Loc, 137 | new IdExprAST(Loc, var->Id), 138 | Name::Dtor), 139 | args); 140 | // Perform semantic on just created expression 141 | cleanupExpr = cleanupExpr->semantic(s); 142 | // Add it to the list 143 | CleanupList.push_back(cleanupExpr); 144 | } 145 | } else if (!isa(*it)) { 146 | // If it's not declaration then we should set atStart to false 147 | atStart = false; 148 | } 149 | 150 | // Check semantic for statement 151 | *it = (*it)->semantic(s); 152 | 153 | // Check for jump statement 154 | if ((*it)->isJump()) { 155 | HasJump = true; 156 | 157 | // Check for return statement 158 | if ((*it)->hasReturn()) { 159 | HasReturn = true; 160 | } 161 | } else { 162 | // It wasn't jump but if it was other block or control statement then 163 | // it could have return statement too 164 | HasJump = (*it)->hasJump(); 165 | HasReturn = (*it)->hasReturn(); 166 | } 167 | } 168 | 169 | // If we need cleanup then we should set some states 170 | if (LandingPad->NeedCleanup) { 171 | // Get escaped function and patch it's NeedCleanup 172 | FuncDeclAST* fncDecl = (s->EnclosedFunc); 173 | fncDecl->LandingPad->NeedCleanup = true; 174 | 175 | if (!LandingPad->Prev->OwnerBlock) { 176 | // If previous landing pad isn't block set NeedCleanup to true 177 | LandingPad->Prev->NeedCleanup = true; 178 | } else { 179 | // Previous landing pad is block but we need set NeedCleanup for it only 180 | // if we have return, continue or break statement in our body 181 | if (LandingPad->Returns || LandingPad->Continues || LandingPad->Breaks) { 182 | LandingPad->Prev->NeedCleanup = true; 183 | } 184 | } 185 | } 186 | 187 | // Remove created scope 188 | s->pop(); 189 | 190 | return this; 191 | } 192 | 193 | // DeclStmtAST implementation 194 | StmtAST* DeclStmtAST::doSemantic(Scope* scope) { 195 | // Check semantic for every declaration 196 | for (SymbolList::iterator it = Decls.begin(), end = Decls.end(); it != end; ++it) { 197 | (*it)->semantic(scope); 198 | (*it)->semantic2(scope); 199 | (*it)->semantic3(scope); 200 | (*it)->semantic4(scope); 201 | (*it)->semantic5(scope); 202 | } 203 | 204 | return this; 205 | } 206 | 207 | // BreakStmtAST implementation 208 | bool BreakStmtAST::hasJump() { 209 | return true; 210 | } 211 | 212 | StmtAST* BreakStmtAST::doSemantic(Scope* scope) { 213 | // We allow break only in the loops 214 | if (!scope->BreakLoc) { 215 | scope->report(Loc, diag::ERR_SemaInvalidJumpStatement); 216 | return nullptr; 217 | } 218 | 219 | // Save break location for later use 220 | BreakLoc = scope->LandingPad; 221 | ++BreakLoc->Breaks; 222 | return this; 223 | } 224 | 225 | // ContinueStmtAST implementation 226 | bool ContinueStmtAST::hasJump() { 227 | return true; 228 | } 229 | 230 | StmtAST* ContinueStmtAST::doSemantic(Scope* scope) { 231 | // We allow continue only in the loops 232 | if (!scope->ContinueLoc) { 233 | scope->report(Loc, diag::ERR_SemaInvalidJumpStatement); 234 | return nullptr; 235 | } 236 | 237 | // Save continue location for later use 238 | ContinueLoc = scope->LandingPad; 239 | ++ContinueLoc->Continues; 240 | return this; 241 | } 242 | 243 | // ReturnStmtAST implementation 244 | bool ReturnStmtAST::hasReturn() { 245 | return true; 246 | } 247 | 248 | bool ReturnStmtAST::hasJump() { 249 | return true; 250 | } 251 | 252 | StmtAST* ReturnStmtAST::doSemantic(Scope* scope) { 253 | assert(scope->LandingPad); 254 | ReturnLoc = scope->LandingPad; 255 | ++ReturnLoc->Returns; 256 | // Check return value 257 | if (Expr) { 258 | // Check for void value function 259 | if (!scope->EnclosedFunc->ReturnType || scope->EnclosedFunc->ReturnType->isVoid()) { 260 | scope->report(Loc, diag::ERR_SemaReturnValueInVoidFunction); 261 | return nullptr; 262 | } 263 | 264 | // Perform semantic of return value 265 | Expr = Expr->semantic(scope); 266 | 267 | if (!scope->EnclosedFunc->ReturnType->equal(Expr->ExprType)) { 268 | Expr = new CastExprAST(Loc, Expr, scope->EnclosedFunc->ReturnType); 269 | Expr = Expr->semantic(scope); 270 | } 271 | 272 | return this; 273 | } 274 | 275 | // We don't have return value check should function have return value or not 276 | if (scope->EnclosedFunc->ReturnType && !scope->EnclosedFunc->ReturnType->isVoid()) { 277 | scope->report(Loc, diag::ERR_SemaReturnVoidFromFunction); 278 | return nullptr; 279 | } 280 | 281 | return this; 282 | } 283 | 284 | // WhileStmtAST implementation 285 | bool WhileStmtAST::hasReturn() { 286 | // Always return false because loop can has 0 iterations 287 | return false; 288 | } 289 | 290 | StmtAST* WhileStmtAST::doSemantic(Scope* scope) { 291 | // Perform semantic of a condition 292 | Cond = Cond->semantic(scope); 293 | 294 | // Condition should has non void type 295 | if (!Cond->ExprType || Cond->ExprType->isVoid()) { 296 | scope->report(Loc, diag::ERR_SemaConditionIsVoid); 297 | return nullptr; 298 | } 299 | 300 | // Check for conversion of conditional expression to boolean 301 | if (!Cond->ExprType->implicitConvertTo(BuiltinTypeAST::get(TypeAST::TI_Bool))) { 302 | scope->report(Loc, diag::ERR_SemaCantConvertToBoolean); 303 | return nullptr; 304 | } 305 | 306 | // Backup old break and continue locations if any 307 | StmtAST* oldBreak = scope->BreakLoc; 308 | StmtAST* oldContinue = scope->ContinueLoc; 309 | 310 | // Set new break and continue locations to this instance 311 | scope->BreakLoc = this; 312 | scope->ContinueLoc = this; 313 | // Create new landing pad 314 | LandingPad = new LandingPadAST(scope->LandingPad, false); 315 | LandingPad->NeedCleanup = scope->LandingPad->NeedCleanup; 316 | LandingPad->IsLoop = true; 317 | scope->LandingPad = LandingPad; 318 | 319 | Body = Body->semantic(scope); 320 | 321 | // Restore old break and continue locations 322 | scope->BreakLoc = oldBreak; 323 | scope->ContinueLoc = oldContinue; 324 | scope->LandingPad = LandingPad->Prev; 325 | 326 | if (PostExpr) { 327 | // Perform semantic for PostExpr if this instance was for-loop before semantic 328 | PostExpr = PostExpr->semantic(scope); 329 | } 330 | 331 | return this; 332 | } 333 | 334 | // ForStmtAST implementation 335 | StmtAST* ForStmtAST::doSemantic(Scope* scope) { 336 | // Rewrite for-loop statement to 337 | // { 338 | // init 339 | // while (cond) { 340 | // body 341 | // continueZone: post 342 | // } 343 | // } 344 | 345 | StmtAST* init = nullptr; 346 | 347 | // We should convert initialization expression or declaration to new 348 | // statement 349 | if (InitExpr) { 350 | init = new ExprStmtAST(Loc, InitExpr); 351 | } else if (!InitDecls.empty()) { 352 | init = new DeclStmtAST(Loc, InitDecls); 353 | } 354 | 355 | // We have different cases for loop with non empty and empty condition 356 | if (Cond) { 357 | StmtList stmts; 358 | 359 | // Add initialization as 1st member of new block statement (if was set) 360 | if (init) { 361 | stmts.push_back(init); 362 | } 363 | 364 | // Create new while-loop and add it as 2nd statement for the block 365 | WhileStmtAST* newLoop = new WhileStmtAST(Loc, Cond, Body); 366 | newLoop->PostExpr = Post; 367 | stmts.push_back(newLoop); 368 | 369 | // Clear and delete this 370 | InitExpr = nullptr; 371 | InitDecls.clear(); 372 | Cond = nullptr; 373 | Post = nullptr; 374 | Body = nullptr; 375 | delete this; 376 | 377 | // Create new block statement and perform semantic on it 378 | StmtAST* res = new BlockStmtAST(Loc, stmts); 379 | return res->semantic(scope); 380 | } else { 381 | StmtList stmts; 382 | 383 | // Add initialization as 1st member of new block statement (if was set) 384 | if (init) { 385 | stmts.push_back(init); 386 | } 387 | 388 | // Create new while-loop and add it as 2nd statement for the block 389 | WhileStmtAST* newLoop = new WhileStmtAST(Loc, new IntExprAST(Loc, 1), Body); 390 | newLoop->PostExpr = Post; 391 | stmts.push_back(newLoop); 392 | 393 | // Clear and delete this 394 | InitExpr = nullptr; 395 | InitDecls.clear(); 396 | Cond = nullptr; 397 | Post = nullptr; 398 | Body = nullptr; 399 | delete this; 400 | 401 | // Create new block statement and perform semantic on it 402 | StmtAST* res = new BlockStmtAST(Loc, stmts); 403 | return res->semantic(scope); 404 | } 405 | } 406 | 407 | // IfStmtAST implementation 408 | bool IfStmtAST::hasReturn() { 409 | if (!ElseBody) { 410 | return false; 411 | } 412 | 413 | // We should return true if both then and else parts have return 414 | return ThenBody->hasReturn() && ElseBody->hasReturn(); 415 | } 416 | 417 | bool IfStmtAST::hasJump() { 418 | if (!ElseBody) { 419 | return false; 420 | } 421 | 422 | // We should return true if both then and else parts have jumps 423 | return ThenBody->hasJump() && ElseBody->hasJump(); 424 | } 425 | 426 | StmtAST* IfStmtAST::doSemantic(Scope* scope) { 427 | // Perform semantic for condition expression 428 | Cond = Cond->semantic(scope); 429 | 430 | // We not allow void condition expression 431 | if (!Cond->ExprType || Cond->ExprType == BuiltinTypeAST::get(TypeAST::TI_Void)) { 432 | scope->report(Loc, diag::ERR_SemaConditionIsVoid); 433 | return nullptr; 434 | } 435 | 436 | if (!Cond->ExprType->implicitConvertTo(BuiltinTypeAST::get(TypeAST::TI_Bool))) { 437 | scope->report(Loc, diag::ERR_SemaCantConvertToBoolean); 438 | return nullptr; 439 | } 440 | 441 | // Create new landing pad 442 | LandingPad = new LandingPadAST(scope->LandingPad, false); 443 | LandingPad->NeedCleanup = scope->LandingPad->NeedCleanup; 444 | scope->LandingPad = LandingPad; 445 | 446 | // Perform semantic for then and else parts 447 | ThenBody = ThenBody->semantic(scope); 448 | 449 | if (ElseBody) { 450 | ElseBody = ElseBody->semantic(scope); 451 | } 452 | 453 | // Restore old landing pad 454 | scope->LandingPad = LandingPad->Prev; 455 | 456 | return this; 457 | } 458 | 459 | } // namespace simple -------------------------------------------------------------------------------- /lib/CodeGen/Decls.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/AST/AST.h" 2 | 3 | using namespace llvm; 4 | 5 | cl::opt< std::string > OutputFilename("o", cl::desc("Specify output filename"), 6 | cl::value_desc("filename")); 7 | 8 | namespace simple { 9 | 10 | Value* SymbolAST::getValue(SLContext& ) { 11 | assert(0 && "SymbolAST::getValue should never be reached"); 12 | return nullptr; 13 | } 14 | 15 | Value* SymbolAST::generateCode(SLContext& Context) { 16 | assert(0 && "SymbolAST::generateCode should never be reached"); 17 | return nullptr; 18 | } 19 | 20 | Value* VarDeclAST::generateCode(SLContext& Context) { 21 | assert(SemaState >= 5); 22 | // Get address of variable and generate code for an initialization 23 | Value* val = getValue(Context); 24 | 25 | // Special case for class variables with constructors 26 | if (Val && isa(ThisType)) { 27 | Val->getRValue(Context); 28 | return val; 29 | } 30 | 31 | // If we have initialization we should generate code for it 32 | if (Val) { 33 | Value* init; 34 | 35 | // Check for pointer 36 | if (isa(ThisType)) { 37 | // For integral constant generate null 38 | if (Val->isIntConst()) { 39 | init = ConstantPointerNull::get((PointerType*)ThisType->getType()); 40 | } else { 41 | if (isa(Val->ExprType)) { 42 | init = Val->getLValue(Context); 43 | Value* tmp = getConstInt(0); 44 | 45 | std::vector< Value* > idx; 46 | 47 | idx.push_back(tmp); 48 | idx.push_back(tmp); 49 | 50 | if (isa(init)) { 51 | AllocaInst *alloca = (AllocaInst*)init; 52 | 53 | init = Context.TheBuilder->CreateGEP(alloca->getAllocatedType(), init, idx); 54 | } else { 55 | assert(0); 56 | } 57 | } else { 58 | init = Val->getRValue(Context); 59 | } 60 | } 61 | } else { 62 | // Otherwise generate code for initialization 63 | init = Val->getRValue(Context); 64 | } 65 | 66 | // Create store instruction 67 | return Context.TheBuilder->CreateStore(init, val); 68 | } 69 | 70 | return val; 71 | } 72 | 73 | Value* VarDeclAST::getValue(SLContext& Context) { 74 | // We should create value only once 75 | if (CodeValue) { 76 | return CodeValue; 77 | } 78 | 79 | // Create alloca instruction for this variable 80 | CodeValue = Context.TheBuilder->CreateAlloca(ThisType->getType(), 81 | nullptr, StringRef(Id->Id, Id->Length)); 82 | return CodeValue; 83 | } 84 | 85 | Value* StructDeclAST::getValue(SLContext& Context) { 86 | // Make sure that type was generated 87 | ThisType->getType(); 88 | return nullptr; 89 | } 90 | 91 | Value* StructDeclAST::generateCode(SLContext& Context) { 92 | assert(SemaState >= 5); 93 | // Make sure that type was generated 94 | ThisType->getType(); 95 | return nullptr; 96 | } 97 | 98 | Value* VTableAST::generateCode(SLContext& Context) { 99 | if (CodeValue) { 100 | return CodeValue; 101 | } 102 | 103 | // Allocate virtual table (all slots will be filled later) 104 | std::vector< Constant* > vtblEntries(CurOffset); 105 | 106 | // Check every function and overload set in the virtual table 107 | for (SymbolMap::iterator it = Decls.begin(), end = Decls.end(); 108 | it != end; ++it) { 109 | if (isa(it->second)) { 110 | // It's overload set 111 | OverloadSetAST* overloadSet = (OverloadSetAST*)it->second; 112 | 113 | // Check every function in the overload set 114 | for (SymbolList::iterator it2 = overloadSet->Vars.begin(), 115 | end2 = overloadSet->Vars.end(); it2 != end2; ++it2) { 116 | FuncDeclAST* fnc = (FuncDeclAST*)*it2; 117 | // Add function to the appropriate slot 118 | vtblEntries[fnc->OffsetOf] = ConstantExpr::getBitCast( 119 | (Function*)fnc->getValue(Context), 120 | PointerType::get( 121 | getGlobalContext(), 122 | getSLContext().TheTarget->getProgramAddressSpace() 123 | ) 124 | ); 125 | } 126 | } else { 127 | // It's function 128 | FuncDeclAST* fnc = (FuncDeclAST*)it->second; 129 | // Add function to the appropriate slot 130 | vtblEntries[fnc->OffsetOf] = ConstantExpr::getBitCast( 131 | (Function*)fnc->getValue(Context), 132 | PointerType::get( 133 | getGlobalContext(), 134 | getSLContext().TheTarget->getProgramAddressSpace() 135 | ) 136 | ); 137 | } 138 | } 139 | 140 | llvm::SmallString< 128 > s; 141 | llvm::raw_svector_ostream output(s); 142 | 143 | // Generate name for virtual function's table 144 | output << "_PTV"; 145 | mangleAggregateName(output, Parent); 146 | 147 | // Create array of int8* 148 | ArrayType* tableType = ArrayType::get( 149 | PointerType::get( 150 | getGlobalContext(), 151 | getSLContext().TheTarget->getProgramAddressSpace() 152 | ), 153 | CurOffset 154 | ); 155 | // Insert virtual table value to the global list of variables 156 | GlobalVariable* val = (GlobalVariable*)Context.TheModule->getOrInsertGlobal( 157 | output.str(), tableType); 158 | // Set virtual function's table data 159 | val->setInitializer(ConstantArray::get(tableType, vtblEntries)); 160 | VTblType = tableType; 161 | 162 | return CodeValue = val; 163 | } 164 | 165 | 166 | llvm::Value* ClassDeclAST::getValue(SLContext& Context) { 167 | ThisType->getType(); 168 | 169 | if (BaseClass) { 170 | BaseClass->getType(); 171 | } 172 | 173 | return nullptr; 174 | } 175 | 176 | llvm::Value* ClassDeclAST::generateCode(SLContext& Context) { 177 | assert(SemaState >= 5); 178 | getValue(Context); 179 | 180 | // Generate code for VTable if needed 181 | if (VTbl) { 182 | VTbl->generateCode(Context); 183 | } 184 | 185 | // Generate code for every struct/class or function declaration in the class 186 | for (SymbolList::iterator it = Vars.begin(), end = Vars.end(); it != end; ++it) { 187 | if (!isa(*it)) { 188 | (*it)->generateCode(Context); 189 | } 190 | } 191 | 192 | return nullptr; 193 | } 194 | 195 | llvm::Value* ParameterSymbolAST::getValue(SLContext& Context) { 196 | // We should create value only once 197 | if (Param->CodeValue) { 198 | return Param->CodeValue; 199 | } 200 | 201 | // Create alloca instruction for this parameter 202 | Param->CodeValue = Context.TheBuilder->CreateAlloca(Param->Param->getType()); 203 | return Param->CodeValue; 204 | } 205 | 206 | llvm::Value* ParameterSymbolAST::generateCode(SLContext& Context) { 207 | assert(SemaState >= 5); 208 | // We need only return value of this parameter other actions will perform 209 | // FuncDeclAST code generation 210 | return getValue(Context); 211 | } 212 | 213 | Value* FuncDeclAST::getValue(SLContext& Context) { 214 | // We should create value only once 215 | if (CodeValue) { 216 | return CodeValue; 217 | } 218 | 219 | SmallString< 128 > str; 220 | raw_svector_ostream output(str); 221 | 222 | // Generate function name (we have special case for main) 223 | if (!(Id->Length == 4 && memcmp(Id->Id, "main", 4) == 0)) { 224 | if (needThis()) { 225 | // For aggregate members we should generate fully qualified name 226 | assert(AggregateSym); 227 | output << "_P"; 228 | mangleAggregateName(output, AggregateSym); 229 | output << Id->Length << StringRef(Id->Id, Id->Length); 230 | ThisType->toMangleBuffer(output); 231 | } else { 232 | // Generate only mangle name 233 | output << "_P" << Id->Length << StringRef(Id->Id, Id->Length); 234 | ThisType->toMangleBuffer(output); 235 | } 236 | } else { 237 | output << "main"; 238 | } 239 | 240 | // Create function with external linkage for this declaration 241 | CodeValue = Function::Create((FunctionType*)ThisType->getType(), 242 | Function::ExternalLinkage, output.str(), nullptr); 243 | Context.TheModule->getFunctionList().push_back(CodeValue); 244 | 245 | return CodeValue; 246 | } 247 | 248 | Value* FuncDeclAST::generateCode(SLContext& Context) { 249 | if (Compiled) { 250 | return CodeValue; 251 | } 252 | 253 | assert(SemaState >= 5); 254 | // Get value for function declaration 255 | getValue(Context); 256 | 257 | BasicBlock* oldBlock = Context.TheBuilder->GetInsertBlock(); 258 | 259 | Function::arg_iterator AI = CodeValue->arg_begin(); 260 | ParameterList::iterator PI = ((FuncTypeAST*)ThisType)->Params.begin(); 261 | ParameterList::iterator PE = ((FuncTypeAST*)ThisType)->Params.end(); 262 | 263 | // Create entry block for function and set it as insert point 264 | BasicBlock* BB = BasicBlock::Create(getGlobalContext(), "entry", CodeValue); 265 | Context.TheBuilder->SetInsertPoint(BB); 266 | 267 | // We need create alloca instructions for every variable declared in the 268 | // function 269 | for (std::vector< SymbolAST* >::iterator it = FuncVars.begin(), end = FuncVars.end(); 270 | it != end; ++it) { 271 | (*it)->getValue(Context); 272 | } 273 | 274 | // Check all function parameters 275 | for ( ; PI != PE; ++PI, ++AI) { 276 | ParameterAST* p = *PI; 277 | 278 | // We need certain actions for named parameter 279 | if (p->Id) { 280 | // Set it's name 281 | AI->setName(StringRef(p->Id->Id, p->Id->Length)); 282 | // Generate alloca instruction (if needed) and store value passed to 283 | // function to named value 284 | if (!p->CodeValue) { 285 | p->CodeValue = Context.TheBuilder->CreateAlloca(p->Param->getType()); 286 | } 287 | 288 | Context.TheBuilder->CreateStore(AI, p->CodeValue); 289 | } 290 | } 291 | 292 | // If function has return type we should add variable which will hold it's 293 | // value 294 | if (!ReturnType->isVoid()) { 295 | LandingPad->ReturnValue = Context.TheBuilder->CreateAlloca( 296 | ReturnType->getType(), 297 | nullptr, 298 | "return.value" 299 | ); 300 | } 301 | 302 | // Create return location and set fall through location 303 | LandingPad->ReturnLoc = BasicBlock::Create(getGlobalContext(), "return.block"); 304 | LandingPad->FallthroughLoc = LandingPad->ReturnLoc; 305 | 306 | // Create cleanup variable if needed 307 | if (LandingPad->NeedCleanup) { 308 | LandingPad->CleanupValue = Context.TheBuilder->CreateAlloca( 309 | Type::getInt32Ty(getGlobalContext()), 310 | 0U, 311 | "cleanup.value" 312 | ); 313 | } 314 | 315 | Function* oldFunction = Context.TheFunction; 316 | Context.TheFunction = CodeValue; 317 | 318 | if (isCtor()) { 319 | // We have special case for constructor 320 | assert(isa(Body)); 321 | assert(isa(Parent)); 322 | BlockStmtAST* blockStmt = (BlockStmtAST*)Body; 323 | ClassDeclAST* classDecl = (ClassDeclAST*)Parent; 324 | VTableAST* parentVtbl = nullptr; 325 | 326 | StmtList::iterator it = blockStmt->Body.begin(); 327 | StmtList::iterator end = blockStmt->Body.end(); 328 | 329 | // If we have base class and it's class and not structure then we probably 330 | // have virtual functions table 331 | if (classDecl->BaseClass) { 332 | // 1st instruction is super variable declaration 333 | (*it)->generateCode(Context); 334 | ++it; 335 | 336 | if (isa(classDecl->BaseClass)) { 337 | ClassDeclAST* baseDecl = (ClassDeclAST*)classDecl->BaseClass->getSymbol(); 338 | parentVtbl = baseDecl->VTbl; 339 | 340 | // Base class can have no constructor. Check it 341 | if (baseDecl->Ctor) { 342 | // We have. Generate code for it's call and advance to next instruction 343 | (*it)->generateCode(Context); 344 | ++it; 345 | } 346 | } 347 | } 348 | 349 | // If our virtual table not equal to base class virtual table then we should 350 | // generate code for it 351 | if (classDecl->VTbl != parentVtbl) { 352 | SymbolAST* thisParam = find(Name::This); 353 | assert(thisParam != nullptr); 354 | // Generate code for this parameter and load it 355 | Value* val = thisParam->getValue(Context); 356 | 357 | val = Context.TheBuilder->CreateLoad( 358 | PointerType::get( 359 | getGlobalContext(), 360 | getSLContext().TheTarget->getProgramAddressSpace() 361 | ), 362 | val 363 | ); 364 | 365 | // Generate code for virtual function's table 366 | Value* vtblVal = classDecl->VTbl->generateCode(Context); 367 | 368 | std::vector< Value* > idx; 369 | 370 | idx.push_back(getConstInt(0)); 371 | idx.push_back(getConstInt(0)); 372 | 373 | // Generate GetElementPtr instruction to get virtual table from globals 374 | vtblVal = Context.TheBuilder->CreateInBoundsGEP(classDecl->VTbl->VTblType, vtblVal, idx); 375 | // Store virtual table in the class instance 376 | val = Context.TheBuilder->CreateStore(vtblVal, val); 377 | } 378 | 379 | // Generate code for rest of the function 380 | blockStmt->generatePartialCode(Context, it, end); 381 | } else if (isDtor()) { 382 | // We have special case for destructor 383 | assert(isa(Body)); 384 | assert(isa(Parent)); 385 | BlockStmtAST* blockStmt = (BlockStmtAST*)Body; 386 | ClassDeclAST* classDecl = (ClassDeclAST*)Parent; 387 | 388 | // If we have base class we should check for call of it's destructor 389 | if (classDecl->BaseClass && isa(classDecl->BaseClass)) { 390 | ClassDeclAST* baseDecl = (ClassDeclAST*)classDecl->BaseClass->getSymbol(); 391 | 392 | // We have special case if we need base class destructor call 393 | if (baseDecl->Dtor) { 394 | StmtList::iterator it = blockStmt->Body.begin(); 395 | StmtList::iterator end = blockStmt->Body.end(); 396 | --end; 397 | 398 | // For destructor we should create new fall through location because 399 | // it can be used during generatePartialCode call 400 | BasicBlock* falthroughBB = BasicBlock::Create(getGlobalContext()); 401 | LandingPad->FallthroughLoc = falthroughBB; 402 | 403 | // Generate code for all members but last 404 | blockStmt->generatePartialCode(Context, it, end); 405 | 406 | // Add or delete fall through block 407 | if (falthroughBB->hasNUsesOrMore(1)) { 408 | CodeValue->getBasicBlockList().push_back(falthroughBB); 409 | Context.TheBuilder->SetInsertPoint(falthroughBB); 410 | } else { 411 | delete falthroughBB; 412 | } 413 | 414 | // Set fall through location back to return location 415 | LandingPad->FallthroughLoc = LandingPad->ReturnLoc; 416 | 417 | // Current instruction should be destructor call. Before it's call 418 | // we should adjust VTbl (we should make sure that they are different, 419 | // but if base class doesn't have VTbl do nothing) 420 | if (classDecl->VTbl != baseDecl->VTbl && baseDecl->VTbl) { 421 | SymbolAST* thisParam = find(Name::This); 422 | assert(!thisParam); 423 | // Generate code for this parameter and load it 424 | Value* val = thisParam->getValue(Context); 425 | val = Context.TheBuilder->CreateLoad( 426 | PointerType::get( 427 | getGlobalContext(), 428 | getSLContext().TheTarget->getProgramAddressSpace() 429 | ), 430 | val 431 | ); 432 | // Generate code for base class virtual function's table 433 | Value* vtblVal = baseDecl->VTbl->generateCode(Context); 434 | 435 | std::vector< Value* > idx; 436 | 437 | idx.push_back(getConstInt(0)); 438 | idx.push_back(getConstInt(0)); 439 | 440 | // Generate GetElementPtr instruction to get virtual table from globals 441 | vtblVal = Context.TheBuilder->CreateInBoundsGEP(baseDecl->VTbl->VTblType, vtblVal, idx); 442 | // Store virtual table in the class instance 443 | val = Context.TheBuilder->CreateStore(vtblVal, val); 444 | } 445 | 446 | // Generate code for base class destructor's call 447 | (*end)->generateCode(Context); 448 | } else { 449 | // We don't need any special handling here 450 | Body->generateCode(Context); 451 | } 452 | } else { 453 | // We don't need any special handling here 454 | Body->generateCode(Context); 455 | } 456 | } else { 457 | // Generate code for function's body 458 | Body->generateCode(Context); 459 | } 460 | 461 | Context.TheFunction = oldFunction; 462 | 463 | // Add return if there was no generated code for return yet 464 | if (!Context.TheBuilder->GetInsertBlock()->getTerminator()) { 465 | Context.TheBuilder->CreateBr(LandingPad->ReturnLoc); 466 | } 467 | 468 | // Add return block to the end of the function and set it as insert point 469 | CodeValue->getBasicBlockList().push_back(LandingPad->ReturnLoc); 470 | Context.TheBuilder->SetInsertPoint(LandingPad->ReturnLoc); 471 | 472 | // Generate load from return value if we have return value 473 | if (!ReturnType->isVoid()) { 474 | Value* ret = Context.TheBuilder->CreateLoad( 475 | ReturnType->getType(), 476 | LandingPad->ReturnValue 477 | ); 478 | Context.TheBuilder->CreateRet(ret); 479 | } else { 480 | // Return void 481 | Context.TheBuilder->CreateRetVoid(); 482 | } 483 | 484 | // Restore old insert point if needed 485 | if (oldBlock) { 486 | Context.TheBuilder->SetInsertPoint(oldBlock); 487 | } 488 | 489 | Function::BasicBlockListType &blocksList = CodeValue->getBasicBlockList(); 490 | 491 | for (Function::BasicBlockListType::iterator it = blocksList.begin(), lastBlock = blocksList.end(); 492 | it != lastBlock; ) { 493 | if (!it->getTerminator()) { 494 | Function::BasicBlockListType::iterator cur = it; 495 | 496 | ++it; 497 | 498 | blocksList.erase(cur); 499 | } else { 500 | ++it; 501 | } 502 | } 503 | 504 | // Verify function's body and run optimization 505 | verifyFunction(*CodeValue, &llvm::errs()); 506 | 507 | Compiled = true; 508 | 509 | return CodeValue; 510 | } 511 | 512 | void ModuleDeclAST::generateCode() { 513 | SLContext& Context = getSLContext(); 514 | 515 | // Generate code for every declaration 516 | for (SymbolList::iterator it = Members.begin(), end = Members.end(); 517 | it != end; ++it) { 518 | (*it)->generateCode(Context); 519 | } 520 | 521 | Context.TheModule->dump(); 522 | 523 | if (!OutputFilename.empty()) { 524 | std::error_code errorInfo; 525 | raw_fd_ostream fd(OutputFilename.c_str(), errorInfo); 526 | 527 | if (errorInfo) { 528 | llvm::errs() << "Can't write to \"" << OutputFilename.c_str() << "\" file\n"; 529 | } 530 | 531 | // Print module's content 532 | Context.TheModule->print(fd, 0); 533 | } 534 | 535 | MainPtr = (double (*)())(intptr_t)getJITMain(); 536 | } 537 | 538 | } // namespace simple -------------------------------------------------------------------------------- /lib/CodeGen/Stmts.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/AST/AST.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace simple { 6 | 7 | Value* StmtAST::generateCode(SLContext& Context) { 8 | assert(0 && "StmtAST::generateCode should never be reached"); 9 | return nullptr; 10 | } 11 | 12 | Value* ExprStmtAST::generateCode(SLContext& Context) { 13 | if (Expr) { 14 | // Generate code for an expression 15 | return Expr->getRValue(Context); 16 | } 17 | 18 | return nullptr; 19 | } 20 | 21 | llvm::Value* BlockStmtAST::generatePartialCode(SLContext& Context, 22 | StmtList::iterator it, StmtList::iterator end) { 23 | // Get break, continue and return locations from parent landing pad 24 | LandingPadAST* parent = LandingPad->Prev; 25 | LandingPad->BreakLoc = parent->BreakLoc; 26 | LandingPad->ContinueLoc = parent->ContinueLoc; 27 | LandingPad->ReturnLoc = parent->ReturnLoc; 28 | 29 | // We should set CleanupLoc differently for case without and with cleanup 30 | if (!LandingPad->NeedCleanup || CleanupList.empty()) { 31 | // Without cleanup we get CleanupLoc from previous landing pad 32 | LandingPad->CleanupLoc = parent->CleanupLoc; 33 | } else { 34 | // We need to add new CleanupLoc if we need cleanup 35 | LandingPad->CleanupLoc = BasicBlock::Create(getGlobalContext()); 36 | } 37 | 38 | // Create new block for FalltrhoughLoc 39 | LandingPad->FallthroughLoc = BasicBlock::Create(getGlobalContext(), "block"); 40 | 41 | StmtAST* lastStmt = nullptr; 42 | BasicBlock* lastFallThrough = nullptr; 43 | BasicBlock* lastInsertionPoint = nullptr; 44 | 45 | // Generate code for every nested statement 46 | for (; it != end; ++it) { 47 | // Save FallthroughLoc 48 | BasicBlock* fallthroughBB = LandingPad->FallthroughLoc; 49 | lastFallThrough = LandingPad->FallthroughLoc; 50 | 51 | lastStmt = *it; 52 | // Generate code for nested statement 53 | lastStmt->generateCode(Context); 54 | 55 | // Check was FallthroughLoc used in nested statement or not 56 | if (!LandingPad->FallthroughLoc) { 57 | // It was. Add it fall through block the end of the function and set 58 | // it as insert point 59 | lastInsertionPoint = Context.TheBuilder->GetInsertBlock(); 60 | Context.TheFunction->getBasicBlockList().push_back(fallthroughBB); 61 | Context.TheBuilder->SetInsertPoint(fallthroughBB); 62 | 63 | // Create new block for FallthroughLoc 64 | LandingPad->FallthroughLoc = BasicBlock::Create(getGlobalContext(), "block"); 65 | } 66 | } 67 | 68 | // Calculate numbers of break, continue and return statements 69 | parent->Breaks += LandingPad->Breaks; 70 | parent->Continues += LandingPad->Continues; 71 | parent->Returns += LandingPad->Returns; 72 | 73 | // Check do we need cleanup or not 74 | if (LandingPad->NeedCleanup) { 75 | // We need 76 | 77 | if (!LandingPad->FallthroughLoc->hasNUsesOrMore(1)) { 78 | // Block wasn't used delete it 79 | delete LandingPad->FallthroughLoc; 80 | } 81 | 82 | // If we don't have any cleanup variables then we don't need any actions 83 | if (CleanupList.empty()) { 84 | if (!Context.TheBuilder->GetInsertBlock()->getTerminator()) { 85 | Context.TheBuilder->CreateBr(parent->FallthroughLoc); 86 | parent->FallthroughLoc = nullptr; 87 | return nullptr; 88 | } 89 | 90 | return nullptr; 91 | } 92 | 93 | // If last current block doesn't have terminator we should add jump 94 | // to cleanup location 95 | if (!Context.TheBuilder->GetInsertBlock()->getTerminator()) { 96 | if (lastStmt && isa(lastStmt) && ((BlockStmtAST*)lastStmt)->IsPromoted) { 97 | Context.TheBuilder->CreateBr(LandingPad->CleanupLoc); 98 | } else { 99 | // We should set fall through value 100 | Context.TheBuilder->CreateStore(getConstInt(0), parent->getCleanupValue()); 101 | Context.TheBuilder->CreateBr(LandingPad->CleanupLoc); 102 | } 103 | } 104 | 105 | // Add cleanup location to the end of the function and set it as insert point 106 | Context.TheFunction->getBasicBlockList().push_back(LandingPad->CleanupLoc); 107 | Context.TheBuilder->SetInsertPoint(LandingPad->CleanupLoc); 108 | LandingPad->CleanupLoc->setName("cleanup.block"); 109 | 110 | // Generated destructor calls in reverse order 111 | for (ExprList::reverse_iterator it = CleanupList.rbegin(), end = CleanupList.rend(); 112 | it != end; ++it) { 113 | (*it)->getRValue(Context); 114 | } 115 | 116 | // Check do we have return, break or continue statements or not 117 | if (!LandingPad->Returns && !LandingPad->Breaks && !LandingPad->Continues) { 118 | // We don't and we should create jump to FallthroughLoc 119 | Context.TheBuilder->CreateBr(parent->FallthroughLoc); 120 | parent->FallthroughLoc = nullptr; 121 | } else { 122 | // Does parent landing pad has CleanupLoc or not 123 | if (parent->CleanupLoc) { 124 | if (IsPromoted) { 125 | Context.TheBuilder->CreateBr(parent->FallthroughLoc); 126 | } else { 127 | // It has we need to create switch with fall through and cleanup locations 128 | Value* val = Context.TheBuilder->CreateLoad( 129 | Type::getInt32Ty(getGlobalContext()), 130 | LandingPad->getCleanupValue() 131 | ); 132 | SwitchInst* switchBB = Context.TheBuilder->CreateSwitch(val, parent->CleanupLoc); 133 | 134 | switchBB->addCase(getConstInt(0), parent->FallthroughLoc); 135 | } 136 | } else { 137 | // It's root cleanup 138 | LandingPadAST* prev = parent; 139 | 140 | // Try to find previous landing pad with cleanup 141 | while (prev->Prev) { 142 | if (prev->CleanupLoc) { 143 | break; 144 | } 145 | 146 | prev = prev->Prev; 147 | } 148 | 149 | // Does parent have cleanup location 150 | if (prev->CleanupLoc) { 151 | // It does. We need to generate switch with cleanup and fall through 152 | // locations and probably also with continue and break 153 | Value* val = Context.TheBuilder->CreateLoad( 154 | Type::getInt32Ty(getGlobalContext()), 155 | LandingPad->getCleanupValue() 156 | ); 157 | SwitchInst* switchBB = Context.TheBuilder->CreateSwitch(val, prev->CleanupLoc); 158 | 159 | switchBB->addCase(getConstInt(0), parent->FallthroughLoc); 160 | 161 | // If we have continue then we should add case for it 162 | if (LandingPad->Continues) { 163 | switchBB->addCase(getConstInt(2), parent->ContinueLoc); 164 | } 165 | 166 | // If we have break then we should add case for it 167 | if (LandingPad->Breaks) { 168 | switchBB->addCase(getConstInt(3), parent->BreakLoc); 169 | } 170 | } else { 171 | if (LandingPad->Returns || LandingPad->Breaks || LandingPad->Continues) { 172 | if (prev->ReturnLoc == parent->FallthroughLoc && !LandingPad->Breaks 173 | && !LandingPad->Continues) { 174 | Context.TheBuilder->CreateBr(prev->ReturnLoc); 175 | } else { 176 | // We should create switch 177 | Value* val = Context.TheBuilder->CreateLoad( 178 | Type::getInt32Ty(getGlobalContext()), 179 | LandingPad->getCleanupValue() 180 | ); 181 | SwitchInst* switchBB = Context.TheBuilder->CreateSwitch(val, prev->ReturnLoc); 182 | 183 | switchBB->addCase(getConstInt(0), parent->FallthroughLoc); 184 | 185 | // If we have continue then we should add case for it 186 | if (LandingPad->Continues) { 187 | switchBB->addCase(getConstInt(2), parent->ContinueLoc); 188 | } 189 | 190 | // If we have break then we should add case for it 191 | if (LandingPad->Breaks) { 192 | switchBB->addCase(getConstInt(3), parent->BreakLoc); 193 | } 194 | } 195 | } else { 196 | // We don't have previous blocks and don't have return. Jump to 197 | // fall through 198 | Context.TheBuilder->CreateBr(parent->FallthroughLoc); 199 | } 200 | } 201 | } 202 | 203 | parent->FallthroughLoc = nullptr; 204 | } 205 | } else { 206 | // We don't have cleanup 207 | 208 | // If last current block doesn't have terminator we should add jump 209 | // to fall through location 210 | if (!Context.TheBuilder->GetInsertBlock()->getTerminator()) { 211 | const unsigned u = Context.TheBuilder->GetInsertBlock()->size(); 212 | 213 | if (u == 0) { 214 | BasicBlock *thisBlock = Context.TheBuilder->GetInsertBlock(); 215 | 216 | if (thisBlock->hasNUses(1)) { 217 | BasicBlock *prevBlock = thisBlock->getSinglePredecessor(); 218 | Instruction *prevTerminator = prevBlock->getTerminator(); 219 | 220 | if (parent->IsLoop) { 221 | thisBlock->replaceAllUsesWith(parent->FallthroughLoc); 222 | } 223 | 224 | if (!LandingPad->FallthroughLoc->hasNUsesOrMore(1)) { 225 | delete LandingPad->FallthroughLoc; 226 | } 227 | 228 | return nullptr; 229 | } 230 | } 231 | 232 | Context.TheBuilder->CreateBr(parent->FallthroughLoc); 233 | parent->FallthroughLoc = nullptr; 234 | 235 | if (!LandingPad->FallthroughLoc->hasNUsesOrMore(1)) { 236 | delete LandingPad->FallthroughLoc; 237 | } 238 | // We need to add fall through block if was used 239 | } else if (LandingPad->FallthroughLoc->hasNUsesOrMore(1)) { 240 | // Add fall through block to the end of the function and create jump to 241 | // parent's fall through block 242 | Context.TheFunction->getBasicBlockList().push_back(LandingPad->FallthroughLoc); 243 | Context.TheBuilder->SetInsertPoint(LandingPad->FallthroughLoc); 244 | Context.TheBuilder->CreateBr(parent->FallthroughLoc); 245 | parent->FallthroughLoc = nullptr; 246 | } else { 247 | delete LandingPad->FallthroughLoc; 248 | } 249 | } 250 | 251 | return nullptr; 252 | } 253 | 254 | Value* BlockStmtAST::generateCode(SLContext& Context) { 255 | return generatePartialCode(Context, Body.begin(), Body.end()); 256 | } 257 | 258 | Value* DeclStmtAST::generateCode(SLContext& Context) { 259 | // Generate code for every declaration 260 | for (SymbolList::iterator it = Decls.begin(), end = Decls.end(); it != end; ++it) { 261 | (*it)->generateCode(Context); 262 | } 263 | 264 | return nullptr; 265 | } 266 | 267 | // LandingPadAST implementation 268 | Value* LandingPadAST::getReturnValue() { 269 | LandingPadAST* prev = this; 270 | 271 | // Find root landing pad 272 | while (prev->Prev) { 273 | prev = prev->Prev; 274 | } 275 | 276 | // Return it's return variable 277 | return prev->ReturnValue; 278 | } 279 | 280 | Value* LandingPadAST::getCleanupValue() { 281 | LandingPadAST* prev = this; 282 | 283 | // Find root landing pad 284 | while (prev->Prev) { 285 | prev = prev->Prev; 286 | } 287 | 288 | // Return it's cleanup variable 289 | return prev->CleanupValue; 290 | } 291 | 292 | Value* BreakStmtAST::generateCode(SLContext& Context) { 293 | // Create jump to break location 294 | if (BreakLoc->NeedCleanup) { 295 | // If we need cleanup then we should save 3 to cleanup variable and jump 296 | // to cleanup location 297 | Context.TheBuilder->CreateStore(getConstInt(3), BreakLoc->getCleanupValue()); 298 | Context.TheBuilder->CreateBr(BreakLoc->CleanupLoc); 299 | return nullptr; 300 | } 301 | 302 | // Create jump to break location 303 | Context.TheBuilder->CreateBr(BreakLoc->BreakLoc); 304 | return nullptr; 305 | } 306 | 307 | Value* ContinueStmtAST::generateCode(SLContext& Context) { 308 | // Create jump to continue location 309 | if (ContinueLoc->NeedCleanup) { 310 | // If we need cleanup then we should save 2 to cleanup variable and jump 311 | // to cleanup location 312 | Context.TheBuilder->CreateStore(getConstInt(2), ContinueLoc->getCleanupValue()); 313 | Context.TheBuilder->CreateBr(ContinueLoc->CleanupLoc); 314 | return nullptr; 315 | } 316 | 317 | // Create jump to continue location 318 | Context.TheBuilder->CreateBr(ContinueLoc->ContinueLoc); 319 | return nullptr; 320 | } 321 | 322 | Value* ReturnStmtAST::generateCode(SLContext& Context) { 323 | if (ReturnLoc->NeedCleanup) { 324 | // If we need cleanup then we should save 1 to cleanup variable and jump 325 | // to cleanup location 326 | Context.TheBuilder->CreateStore(getConstInt(1), ReturnLoc->getCleanupValue()); 327 | 328 | if (Expr) { 329 | // If we have return value we should store it to return variable 330 | Value* retVal = Expr->getRValue(Context); 331 | Context.TheBuilder->CreateStore(retVal, ReturnLoc->getReturnValue()); 332 | } 333 | 334 | // Create jump to cleanup location 335 | Context.TheBuilder->CreateBr(ReturnLoc->CleanupLoc); 336 | return nullptr; 337 | } 338 | 339 | // Check return value 340 | if (Expr) { 341 | // Generate code for return value and create return instruction 342 | Value* retVal = Expr->getRValue(Context); 343 | Context.TheBuilder->CreateStore(retVal, ReturnLoc->getReturnValue()); 344 | Context.TheBuilder->CreateBr(ReturnLoc->ReturnLoc); 345 | return nullptr; 346 | } 347 | 348 | // Generate void return instruction 349 | Context.TheBuilder->CreateBr(ReturnLoc->ReturnLoc); 350 | return nullptr; 351 | } 352 | 353 | Value* WhileStmtAST::generateCode(SLContext& Context) { 354 | LandingPadAST* prev = LandingPad->Prev; 355 | LandingPad->ReturnLoc = prev->ReturnLoc; 356 | 357 | // We have special case for loop with constant value condition 358 | if (Cond->isConst()) { 359 | // For loop with false condition we don't need any generated code 360 | if (!Cond->isTrue()) { 361 | return nullptr; 362 | } 363 | 364 | // Get blocks for body of the loop and post loop (also store them for 365 | // break and continue locations) 366 | BasicBlock* bodyBB = LandingPad->ContinueLoc = BasicBlock::Create(getGlobalContext(), 367 | "loopbody", Context.TheFunction); 368 | BasicBlock* endBB = LandingPad->BreakLoc = BasicBlock::Create(getGlobalContext(), 369 | "loopend"); 370 | 371 | if (PostExpr) { 372 | // For ex for-loop we should create block for post expression too and 373 | // it will also be location for continue 374 | LandingPad->ContinueLoc = BasicBlock::Create(getGlobalContext(), "postbody"); 375 | } 376 | 377 | // Create jump to body branch and set body branch as insertion point 378 | Context.TheBuilder->CreateBr(bodyBB); 379 | Context.TheBuilder->SetInsertPoint(bodyBB); 380 | 381 | // Set fall through location to appropriate location 382 | if (PostExpr) { 383 | LandingPad->FallthroughLoc = LandingPad->ContinueLoc; 384 | } else { 385 | LandingPad->FallthroughLoc = bodyBB; 386 | } 387 | 388 | // Generate code for loop's body 389 | Body->generateCode(Context); 390 | 391 | // We have special case for ex for-loop 392 | if (PostExpr) { 393 | // Add continue branch to the end of the function and set it as insertion 394 | // point 395 | Context.TheFunction->getBasicBlockList().push_back(LandingPad->ContinueLoc); 396 | Context.TheBuilder->SetInsertPoint(LandingPad->ContinueLoc); 397 | 398 | // Generate code for post expression and create jump to body of the loop 399 | PostExpr->getRValue(Context); 400 | Context.TheBuilder->CreateBr(bodyBB); 401 | } 402 | 403 | // Add end branch to the end of the function and set it as insertion 404 | // point 405 | Context.TheFunction->getBasicBlockList().push_back(endBB); 406 | Context.TheBuilder->SetInsertPoint(endBB); 407 | prev->Returns += LandingPad->Returns; 408 | 409 | return nullptr; 410 | } 411 | 412 | // Get blocks for condition, body of the loop and post loop (also store them 413 | // for break and continue locations) 414 | BasicBlock* condBB = LandingPad->ContinueLoc = BasicBlock::Create(getGlobalContext(), 415 | "loopcond", Context.TheFunction); 416 | BasicBlock* bodyBB = BasicBlock::Create(getGlobalContext(), "loopbody"); 417 | BasicBlock* endBB = LandingPad->BreakLoc = BasicBlock::Create(getGlobalContext(), "loopend"); 418 | 419 | if (PostExpr) { 420 | // For ex for-loop we should create block for post expression too and 421 | // it will also be location for continue 422 | LandingPad->ContinueLoc = BasicBlock::Create(getGlobalContext(), "postbody"); 423 | } 424 | 425 | // Create jump to condition branch and set continue branch as insertion point 426 | Context.TheBuilder->CreateBr(condBB); 427 | Context.TheBuilder->SetInsertPoint(condBB); 428 | 429 | // Generate code for condition 430 | Value* cond = Cond->getRValue(Context); 431 | // Promote result to bool 432 | cond = promoteToBool(cond, Cond->ExprType, *Context.TheBuilder); 433 | // Create jump to either body of the loop or it's end based on condition 434 | // result 435 | Context.TheBuilder->CreateCondBr(cond, bodyBB, endBB); 436 | 437 | // Add body branch to the end of the function and set it as insertion 438 | // point 439 | Context.TheFunction->getBasicBlockList().push_back(bodyBB); 440 | Context.TheBuilder->SetInsertPoint(bodyBB); 441 | 442 | // Set fall through location to appropriate location 443 | if (PostExpr) { 444 | LandingPad->FallthroughLoc = LandingPad->ContinueLoc; 445 | } else { 446 | LandingPad->FallthroughLoc = condBB; 447 | } 448 | 449 | // Generate code for loop's body 450 | Body->generateCode(Context); 451 | 452 | // We have special case for ex for-loop 453 | if (PostExpr) { 454 | // Add continue branch to the end of the function and set it as insertion 455 | // point 456 | Context.TheFunction->getBasicBlockList().push_back(LandingPad->ContinueLoc); 457 | Context.TheBuilder->SetInsertPoint(LandingPad->ContinueLoc); 458 | 459 | // Generate code for post expression and create jump to loop's condition 460 | PostExpr->getRValue(Context); 461 | Context.TheBuilder->CreateBr(condBB); 462 | } 463 | 464 | // Add end branch to the end of the function and set it as insertion 465 | // point 466 | Context.TheFunction->getBasicBlockList().push_back(endBB); 467 | Context.TheBuilder->SetInsertPoint(endBB); 468 | prev->Returns += LandingPad->Returns; 469 | 470 | return nullptr; 471 | } 472 | 473 | llvm::Value* ForStmtAST::generateCode(SLContext& Context) { 474 | assert(0 && "ForStmtAST::semantic should never be reached"); 475 | return nullptr; 476 | } 477 | 478 | 479 | llvm::Value* IfStmtAST::generateCode(SLContext& Context) { 480 | // Get all locations from parent landing pad 481 | LandingPadAST* prev = LandingPad->Prev; 482 | LandingPad->CleanupLoc = prev->CleanupLoc; 483 | LandingPad->ReturnLoc = prev->ReturnLoc; 484 | LandingPad->FallthroughLoc = prev->FallthroughLoc; 485 | LandingPad->ContinueLoc = prev->ContinueLoc; 486 | LandingPad->BreakLoc = prev->BreakLoc; 487 | 488 | // We have special case for if with constant conditional expression 489 | if (Cond->isConst()) { 490 | if (Cond->isTrue()) { 491 | // For true variant generate code for then branch 492 | ThenBody->generateCode(Context); 493 | 494 | // Calculate number of return, break and continue statements for the parent 495 | // landing pad 496 | prev->Returns += LandingPad->Returns; 497 | prev->Breaks += LandingPad->Breaks; 498 | prev->Continues += LandingPad->Continues; 499 | 500 | if (!Context.TheBuilder->GetInsertBlock()->getTerminator()) { 501 | // Create jump to old fall through location 502 | Context.TheBuilder->CreateBr(prev->FallthroughLoc); 503 | prev->FallthroughLoc = nullptr; 504 | } 505 | 506 | return nullptr; 507 | } 508 | 509 | // For false variant generate code for else branch (if exists) 510 | if (ElseBody) { 511 | ElseBody->generateCode(Context); 512 | 513 | // Calculate number of return, break and continue statements for the parent 514 | // landing pad 515 | prev->Returns += LandingPad->Returns; 516 | prev->Breaks += LandingPad->Breaks; 517 | prev->Continues += LandingPad->Continues; 518 | 519 | if (!Context.TheBuilder->GetInsertBlock()->getTerminator()) { 520 | // Create jump to old fall through location 521 | Context.TheBuilder->CreateBr(prev->FallthroughLoc); 522 | prev->FallthroughLoc = nullptr; 523 | } 524 | } 525 | 526 | return nullptr; 527 | } 528 | 529 | // Generate code for condition 530 | Value* cond = Cond->getRValue(Context); 531 | // Promote result to bool 532 | cond = promoteToBool(cond, Cond->ExprType, *Context.TheBuilder); 533 | 534 | // Get blocks for then, else and continue locations 535 | BasicBlock* thenBB = BasicBlock::Create(getGlobalContext(), "thenpart", 536 | Context.TheFunction); 537 | BasicBlock* elseBB = nullptr; 538 | BasicBlock* endBB = BasicBlock::Create(getGlobalContext(), "ifcont"); 539 | 540 | if (ElseBody) { 541 | elseBB = BasicBlock::Create(getGlobalContext(), "elsepart"); 542 | // Create jump to then or else (if else branch exists) 543 | Context.TheBuilder->CreateCondBr(cond, thenBB, elseBB); 544 | } else { 545 | // Create jump to then or continue 546 | Context.TheBuilder->CreateCondBr(cond, thenBB, endBB); 547 | } 548 | 549 | // Set insertion block to then block 550 | Context.TheBuilder->SetInsertPoint(thenBB); 551 | 552 | // We should set fall through location 553 | LandingPad->FallthroughLoc = endBB; 554 | 555 | // Generate code for then body 556 | ThenBody->generateCode(Context); 557 | 558 | // We should set fall through location 559 | LandingPad->FallthroughLoc = endBB; 560 | 561 | // Does else branch exist? 562 | if (ElseBody) { 563 | // Add else branch to the end of the function and set it as insertion 564 | // point 565 | Context.TheFunction->getBasicBlockList().push_back(elseBB); 566 | Context.TheBuilder->SetInsertPoint(elseBB); 567 | 568 | // Generate code for else body 569 | ElseBody->generateCode(Context); 570 | } 571 | 572 | if (endBB->hasNUsesOrMore(1)) { 573 | // Add end branch to the end of the function and set it as insertion 574 | // point 575 | Context.TheFunction->getBasicBlockList().push_back(endBB); 576 | Context.TheBuilder->SetInsertPoint(endBB); 577 | } else { 578 | delete endBB; 579 | } 580 | 581 | // Calculate number of return, break and continue statements for the parent 582 | // landing pad 583 | prev->Returns += LandingPad->Returns; 584 | prev->Breaks += LandingPad->Breaks; 585 | prev->Continues += LandingPad->Continues; 586 | 587 | return nullptr; 588 | } 589 | 590 | } // namespace simple -------------------------------------------------------------------------------- /lib/Parser/Parser.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/Parser/Parser.h" 2 | 3 | namespace simple { 4 | 5 | using llvm::isa; 6 | 7 | Parser::Parser(Lexer *lex) 8 | : Src(lex), 9 | CurPos(Src.begin()) { 10 | } 11 | 12 | void Parser::check(tok::TokenKind tok) { 13 | if (CurPos != tok) { 14 | getDiagnostics().report(CurPos.getLocation(), 15 | diag::ERR_Expected, 16 | tok::toString(tok), 17 | tok::toString(CurPos->getKind())); 18 | } 19 | 20 | ++CurPos; 21 | } 22 | 23 | /// primary-expr 24 | /// ::= floating-point-literal 25 | /// ::= integral-literal 26 | /// ::= '.'? identifier 27 | /// ::= char-literal 28 | /// ::= string-literal 29 | /// ::= '(' expr ')' 30 | /// ::= 'this' 31 | /// ::= 'super' 32 | ExprAST *Parser::parsePrimaryExpr() { 33 | ExprAST *result = nullptr; 34 | 35 | switch (CurPos->getKind()) { 36 | case tok::FloatNumber: 37 | result = new FloatExprAST(CurPos.getLocation(), strtod(CurPos->getLiteral().data(), nullptr)); 38 | ++CurPos; 39 | return result; 40 | 41 | case tok::IntNumber: 42 | result = new IntExprAST(CurPos.getLocation(), atoi(CurPos->getLiteral().data())); 43 | ++CurPos; 44 | return result; 45 | 46 | case tok::CharLiteral: 47 | result = new IntExprAST(CurPos.getLocation(), CurPos->getChar()); 48 | ++CurPos; 49 | return result; 50 | 51 | case tok::StringConstant: 52 | result = new StringExprAST(CurPos.getLocation(), CurPos->getLiteral()); 53 | ++CurPos; 54 | return result; 55 | 56 | case tok::Identifier: 57 | result = new IdExprAST(CurPos.getLocation(), CurPos->getIdentifier()); 58 | ++CurPos; 59 | return result; 60 | 61 | case tok::Dot: 62 | if ((CurPos + 1) != tok::Identifier) { 63 | check(tok::Identifier); 64 | } 65 | // identifier will be parsed in parsePostfixExpr 66 | return new IdExprAST(CurPos.getLocation(), nullptr); 67 | 68 | case tok::Super: 69 | result = new IdExprAST(CurPos.getLocation(), Name::Super); 70 | ++CurPos; 71 | return result; 72 | 73 | case tok::This: 74 | result = new IdExprAST(CurPos.getLocation(), Name::This); 75 | ++CurPos; 76 | return result; 77 | 78 | case tok::OpenParen: 79 | ++CurPos; 80 | result = parseExpr(); 81 | check(tok::CloseParen); 82 | return result; 83 | 84 | default: 85 | getDiagnostics().report(CurPos.getLocation(), diag::ERR_ExpectedExpression); 86 | return nullptr; 87 | } 88 | } 89 | 90 | /// call-arguments 91 | /// ::= assign-expr 92 | /// ::= call-arguments ',' assign-expr 93 | /// postfix-expr 94 | /// ::= primary-expr 95 | /// ::= postfix-expr '++' 96 | /// ::= postfix-expr '--' 97 | /// ::= postfix-expr '(' call-arguments ? ')' 98 | /// ::= postfix-expr '[' expr ']' 99 | /// ::= postfix-expr '.' identifier 100 | ExprAST *Parser::parsePostfixExpr() { 101 | ExprAST *result = parsePrimaryExpr(); 102 | 103 | for (;;) { 104 | llvm::SMLoc loc = CurPos.getLocation(); 105 | 106 | switch (int op = CurPos->getKind()) { 107 | case tok::PlusPlus: 108 | case tok::MinusMinus: 109 | result = new BinaryExprAST(loc, op, result, nullptr); 110 | ++CurPos; 111 | continue; 112 | 113 | case tok::OpenBrace: { 114 | check(tok::OpenBrace); 115 | ExprAST *expr = parseExpr(); 116 | check(tok::CloseBrace); 117 | result = new IndexExprAST(loc, result, expr); 118 | continue; 119 | } 120 | 121 | case tok::OpenParen: { 122 | ++CurPos; 123 | 124 | ExprList args; 125 | 126 | // Check for function call with 0 arguments 127 | if (CurPos != tok::CloseParen) { 128 | for (;;) { 129 | ExprAST *arg = parseAssignExpr(); 130 | args.push_back(arg); 131 | 132 | // If we have , then we should parse at least 1 more argument 133 | if (CurPos != tok::Comma) { 134 | break; 135 | } 136 | 137 | ++CurPos; 138 | } 139 | } 140 | 141 | check(tok::CloseParen); 142 | result = new CallExprAST(loc, result, args); 143 | continue; 144 | } 145 | 146 | case tok::Dot: { 147 | while (CurPos == tok::Dot) { 148 | ++CurPos; 149 | 150 | Name *name = nullptr; 151 | 152 | if (CurPos == tok::Identifier) { 153 | name = CurPos->getIdentifier(); 154 | } 155 | 156 | check(tok::Identifier); 157 | result = new MemberAccessExprAST(loc, result, name); 158 | } 159 | 160 | continue; 161 | } 162 | 163 | default: 164 | return result; 165 | } 166 | } 167 | } 168 | 169 | /// unary-expr 170 | /// ::= postfix-expr 171 | /// ::= '+' unary-expr 172 | /// ::= '-' unary-expr 173 | /// ::= '++' unary-expr 174 | /// ::= '--' unary-expr 175 | /// ::= '~' unary-expr 176 | /// ::= '!' unary-expr 177 | /// ::= '*' unary-expr 178 | /// ::= '&' unary-expr 179 | /// ::= 'del' unary-expr 180 | /// ::= new-expr 181 | /// new-expr 182 | /// ::= 'new' type [' assign-expr ']' 183 | /// ::= 'new' type ('(' call-arguments? ')') ? 184 | ExprAST *Parser::parseUnaryExpr() { 185 | ExprAST *result = nullptr; 186 | llvm::SMLoc loc = CurPos.getLocation(); 187 | 188 | switch (int op = CurPos->getKind()) { 189 | case tok::Plus: 190 | case tok::Minus: 191 | case tok::PlusPlus: 192 | case tok::MinusMinus: 193 | case tok::Not: 194 | case tok::Tilda: 195 | ++CurPos; 196 | result = parseUnaryExpr(); 197 | return new UnaryExprAST(loc, op, result); 198 | 199 | case tok::Mul: 200 | ++CurPos; 201 | result = parseUnaryExpr(); 202 | return new DerefExprAST(loc, result); 203 | 204 | case tok::BitAnd: 205 | ++CurPos; 206 | result = parseUnaryExpr(); 207 | return new AddressOfExprAST(loc, result); 208 | 209 | case tok::Delete: { 210 | ++CurPos; 211 | result = parsePostfixExpr(); 212 | return new DeleteExprAST(loc, result); 213 | } 214 | 215 | case tok::New: { 216 | ++CurPos; 217 | TypeAST *type = parseType(); 218 | ExprList args; 219 | ExprAST *dynamicSize = nullptr; 220 | 221 | // Check for [ expression ] 222 | // Note: [ integral-constant ] could be parsed in parseType 223 | if (CurPos == tok::OpenBrace) { 224 | if (isa(type)) { 225 | getDiagnostics().report(CurPos.getLocation(), 226 | diag::ERR_DynArrayAggregate); 227 | } 228 | 229 | ++CurPos; 230 | dynamicSize = parseAssignExpr(); 231 | check(tok::CloseBrace); 232 | } 233 | 234 | if (isa(type) && CurPos == tok::OpenParen) { 235 | ++CurPos; 236 | 237 | // Check for function call with 0 arguments 238 | if (CurPos != tok::CloseParen) { 239 | for (;;) { 240 | ExprAST *arg = parseAssignExpr(); 241 | args.push_back(arg); 242 | 243 | // If we have , then we should parse at least 1 more argument 244 | if (CurPos != tok::Comma) { 245 | break; 246 | } 247 | 248 | ++CurPos; 249 | } 250 | } 251 | 252 | check(tok::CloseParen); 253 | } 254 | 255 | return new NewExprAST(loc, type, dynamicSize, args); 256 | } 257 | 258 | default: 259 | return parsePostfixExpr(); 260 | } 261 | } 262 | 263 | enum OpPrecedenceLevel { 264 | OPL_Unknown = 0, ///< Not binary operator. 265 | OPL_Comma = 1, ///< , 266 | OPL_Assignment = 2, ///< = 267 | OPL_Conditional = 3, ///< ? 268 | OPL_LogicalOr = 4, ///< || 269 | OPL_LogicalAnd = 5, ///< && 270 | OPL_InclusiveOr = 6, ///< | 271 | OPL_ExclusiveOr = 7, ///< ^ 272 | OPL_And = 8, ///< & 273 | OPL_Equality = 9, ///< ==, != 274 | OPL_Relational = 10, ///< >=, <=, >, < 275 | OPL_Shift = 11, ///< <<, >> 276 | OPL_Additive = 12, ///< -, + 277 | OPL_Multiplicative = 13 ///< *, /, % 278 | }; 279 | 280 | OpPrecedenceLevel getBinOpPrecedence(tok::TokenKind op) { 281 | switch (op) { 282 | case tok::Greater: 283 | case tok::Less: 284 | case tok::GreaterEqual: 285 | case tok::LessEqual: 286 | return OPL_Relational; 287 | 288 | case tok::LShift: 289 | case tok::RShift: 290 | return OPL_Shift; 291 | 292 | case tok::Comma: 293 | return OPL_Comma; 294 | 295 | case tok::Assign: 296 | return OPL_Assignment; 297 | 298 | case tok::Question: 299 | return OPL_Conditional; 300 | 301 | case tok::LogOr: 302 | return OPL_LogicalOr; 303 | 304 | case tok::LogAnd: 305 | return OPL_LogicalAnd; 306 | 307 | case tok::BitOr: 308 | return OPL_InclusiveOr; 309 | 310 | case tok::BitXor: 311 | return OPL_ExclusiveOr; 312 | 313 | case tok::BitAnd: 314 | return OPL_And; 315 | 316 | case tok::Equal: 317 | case tok::NotEqual: 318 | return OPL_Equality; 319 | 320 | case tok::Plus: 321 | case tok::Minus: 322 | return OPL_Additive; 323 | 324 | case tok::Mul: 325 | case tok::Div: 326 | case tok::Mod: 327 | return OPL_Multiplicative; 328 | 329 | default: 330 | return OPL_Unknown; 331 | } 332 | } 333 | 334 | // expr 335 | // ::= assign-expr 336 | // ::= expr ',' assign-expr 337 | // assign-expr 338 | // ::= cond-expr 339 | // ::= cond-expr '=' assign-expr 340 | // cond-expr 341 | // ::= assoc-expr 342 | // ::= assoc-expr '?' expr ':' cond-expr 343 | // op 344 | // ::= '||' | '&&' | '|' | '^' | '&' | '==' | '!=' | '>=' | '<=' | '>' | '<' | '<<' | '>>' | '-' | '+' | '*' | '/' | '%' 345 | // assoc-expr 346 | // ::= unary-expr 347 | // ::= assoc-expr op unary-expr 348 | ExprAST *Parser::parseRHS(ExprAST *lhs, int maxPrec) { 349 | OpPrecedenceLevel newPrec = getBinOpPrecedence(CurPos->getKind()); 350 | 351 | for (;;) { 352 | tok::TokenKind tok = CurPos->getKind(); 353 | llvm::SMLoc loc = CurPos.getLocation(); 354 | 355 | if (newPrec < maxPrec) { 356 | return lhs; 357 | } 358 | 359 | ++CurPos; 360 | 361 | // Check for ? : 362 | if (newPrec == OPL_Conditional) { 363 | ExprAST *thenPart = nullptr; 364 | 365 | if (CurPos == tok::Colon) { 366 | getDiagnostics().report(CurPos.getLocation(), 367 | diag::ERR_ExpectedExpressionAfterQuestion); 368 | } else { 369 | thenPart = parseExpr(); 370 | } 371 | 372 | check(tok::Colon); 373 | 374 | ExprAST *elsePart = parseAssignExpr(); 375 | lhs = new CondExprAST(loc, lhs, thenPart, elsePart); 376 | 377 | newPrec = getBinOpPrecedence(CurPos->getKind()); 378 | continue; 379 | } 380 | 381 | ExprAST *rhs = parseUnaryExpr(); 382 | OpPrecedenceLevel thisPrec = newPrec; 383 | newPrec = getBinOpPrecedence(CurPos->getKind()); 384 | bool isRightAssoc = (thisPrec == OPL_Assignment); 385 | 386 | if (thisPrec < newPrec || (thisPrec == newPrec && isRightAssoc)) { 387 | if (isRightAssoc) { 388 | rhs = parseRHS(rhs, thisPrec); 389 | } else { 390 | rhs = parseRHS(rhs, (OpPrecedenceLevel)(thisPrec + 1)); 391 | } 392 | 393 | newPrec = getBinOpPrecedence(CurPos->getKind()); 394 | } 395 | 396 | lhs = new BinaryExprAST(loc, tok, lhs, rhs); 397 | } 398 | } 399 | 400 | ExprAST *Parser::parseAssignExpr() { 401 | ExprAST *lhs = parseUnaryExpr(); 402 | return parseRHS(lhs, OPL_Assignment); 403 | } 404 | 405 | ExprAST *Parser::parseExpr() { 406 | ExprAST *lhs = parseUnaryExpr(); 407 | return parseRHS(lhs, OPL_Comma); 408 | } 409 | 410 | /// basic-type 411 | /// ::= 'int' 412 | /// ::= 'float' 413 | /// ::= 'void' 414 | /// ::= 'char' 415 | /// ::= 'string' 416 | /// ::= '.'? identifier ('.' identifier)* 417 | /// type 418 | /// ::= basic-type 419 | /// ::= type '*' 420 | /// ::= type '[' integral-literal ']' 421 | TypeAST *Parser::parseType() { 422 | TypeAST *type = nullptr; 423 | bool isVoid = false; 424 | llvm::SMLoc loc = CurPos.getLocation(); 425 | 426 | switch (CurPos->getKind()) { 427 | case tok::Int: 428 | ++CurPos; 429 | type = BuiltinTypeAST::get(TypeAST::TI_Int); 430 | break; 431 | 432 | case tok::Float: 433 | ++CurPos; 434 | type = BuiltinTypeAST::get(TypeAST::TI_Float); 435 | break; 436 | 437 | case tok::Char: 438 | ++CurPos; 439 | type = BuiltinTypeAST::get(TypeAST::TI_Char); 440 | break; 441 | 442 | case tok::String: 443 | ++CurPos; 444 | type = BuiltinTypeAST::get(TypeAST::TI_String); 445 | break; 446 | 447 | case tok::Void: 448 | ++CurPos; 449 | type = BuiltinTypeAST::get(TypeAST::TI_Void); 450 | isVoid = true; 451 | break; 452 | 453 | case tok::Dot: 454 | case tok::Identifier: { 455 | Name *name = nullptr; 456 | QualifiedName qualName; 457 | 458 | if (CurPos == tok::Identifier) { 459 | name = CurPos->getIdentifier(); 460 | ++CurPos; 461 | } 462 | 463 | qualName.push_back(name); 464 | 465 | while (CurPos == tok::Dot) { 466 | ++CurPos; 467 | 468 | if (CurPos == tok::Identifier) { 469 | name = CurPos->getIdentifier(); 470 | } 471 | 472 | check(tok::Identifier); 473 | qualName.push_back(name); 474 | } 475 | 476 | type = new QualifiedTypeAST(qualName); 477 | break; 478 | } 479 | 480 | default: 481 | getDiagnostics().report(CurPos.getLocation(), diag::ERR_InvalidType); 482 | return nullptr; 483 | } 484 | 485 | for (;;) { 486 | switch (CurPos->getKind()) { 487 | case tok::OpenBrace: { 488 | if (isVoid) { 489 | getDiagnostics().report(loc, diag::ERR_VoidAsNonPointer); 490 | return nullptr; 491 | } 492 | 493 | ++CurPos; 494 | 495 | int dim = 0; 496 | 497 | if (CurPos == tok::IntNumber) { 498 | dim = atoi(CurPos->getLiteral().data()); 499 | } else { 500 | // [ expression ] will be parsed later in parseUnaryExpr (in other 501 | // cases it's error) 502 | --CurPos; 503 | break; 504 | } 505 | 506 | check(tok::IntNumber); 507 | check(tok::CloseBrace); 508 | 509 | type = new ArrayTypeAST(type, dim); 510 | continue; 511 | } 512 | 513 | case tok::Mul: 514 | ++CurPos; 515 | type = new PointerTypeAST(type, false); 516 | continue; 517 | 518 | default: 519 | break; 520 | } 521 | 522 | break; 523 | } 524 | 525 | if (type == BuiltinTypeAST::get(TypeAST::TI_Void)) { 526 | getDiagnostics().report(loc, diag::ERR_VoidAsNonPointer); 527 | return nullptr; 528 | } 529 | 530 | return type; 531 | } 532 | 533 | /// parameter ::= identifier ':' type 534 | /// parameters-list 535 | /// ::= parameter 536 | /// ::= parameter-list ',' parameter 537 | /// return-type ::= ':' type 538 | /// func-proto ::= identifier '(' parameters-list ? ')' return-type ? 539 | SymbolAST *Parser::parseFuncProto() { 540 | Name *name = nullptr; 541 | TypeAST *returnType = BuiltinTypeAST::get(TypeAST::TI_Void); 542 | ParameterList params; 543 | int Tok = CurPos->getKind(); 544 | llvm::SMLoc loc = CurPos.getLocation(); 545 | 546 | ++CurPos; 547 | 548 | // Function can start with identifier, new or delete keywords 549 | if (CurPos == tok::Identifier) { 550 | name = CurPos->getIdentifier(); 551 | ++CurPos; 552 | } else if (CurPos == tok::New) { 553 | ++CurPos; 554 | name = Name::New; 555 | } else if (CurPos == tok::Delete) { 556 | ++CurPos; 557 | name = Name::Delete; 558 | } else { 559 | check(tok::Identifier); 560 | } 561 | 562 | check(tok::OpenParen); 563 | 564 | // We should parse all parameters if it's not ( ) 565 | if (CurPos != tok::CloseParen) { 566 | for (;;) { 567 | Name *paramName = nullptr; 568 | 569 | if (CurPos == tok::Identifier) { 570 | paramName = CurPos->getIdentifier(); 571 | ++CurPos; 572 | 573 | // check for anonymouse parameter 574 | if (strcmp(paramName->Id, "_") == 0) { 575 | paramName = nullptr; 576 | } 577 | } else { 578 | check(tok::Identifier); 579 | } 580 | 581 | check(tok::Colon); 582 | 583 | TypeAST *type = parseType(); 584 | 585 | params.push_back(new ParameterAST(type, paramName)); 586 | 587 | if (CurPos != tok::Comma) { 588 | break; 589 | } 590 | 591 | ++CurPos; 592 | } 593 | } 594 | 595 | check(tok::CloseParen); 596 | 597 | // We can have : type to set return type 598 | // Note: : void not allowed 599 | if (CurPos == tok::Colon) { 600 | ++CurPos; 601 | returnType = parseType(); 602 | } 603 | 604 | returnType = new FuncTypeAST(returnType, params); 605 | return new FuncDeclAST(loc, returnType, name, nullptr, false, Tok); 606 | } 607 | 608 | /// func-decl ::= func-decl-kwd func-proto block-stmt 609 | /// func-decl-kwd 610 | /// ::= 'fn' 611 | /// ::= 'virt' 612 | /// ::= 'impl' 613 | SymbolList Parser::parseFuncDecl(bool isClassMember) { 614 | SymbolList result; 615 | FuncDeclAST *decl = (FuncDeclAST *)parseFuncProto(); 616 | 617 | if (CurPos != tok::BlockStart) { 618 | getDiagnostics().report(CurPos.getLocation(), diag::ERR_ExpectedFuncBody); 619 | } else { 620 | StmtAST *body = parseStmt(); 621 | // We should fix some values for declaration 622 | decl->Body = body; 623 | decl->NeedThis = isClassMember; 624 | result.push_back(decl); 625 | } 626 | 627 | return result; 628 | } 629 | 630 | /// decl 631 | /// ::= func-decl 632 | /// ::= dtor-decl 633 | /// ::= struct-decl 634 | /// ::= class-decl 635 | /// 636 | /// decls 637 | /// ::= decl 638 | /// ::= decls decl 639 | /// 640 | /// struct-decl 641 | /// ::= 'struct' identifier '{' decl-stmt * '}' 642 | /// 643 | /// class-decl 644 | /// ::= 'class' identifier ( 'extends' type ) ? '{' decls '}' 645 | /// 646 | /// dtor-decl ::= ('virt' | 'impl')? 'del' '(' ')' block-stmt 647 | /// ctor-decl ::= 'new' '(' parameters-list ? ')' base-ctor-call ? block-stmt 648 | /// base-ctor-call ::= ':' 'super' '(' call-arguments ? ')' 649 | SymbolList Parser::parseDecls(bool isClassMember) { 650 | SymbolList result; 651 | 652 | for (;;) { 653 | SymbolList tmp; 654 | llvm::SMLoc loc = CurPos.getLocation(); 655 | 656 | switch (int Tok = CurPos->getKind()) { 657 | case tok::Virtual: 658 | case tok::Override: 659 | if (!isClassMember) { 660 | getDiagnostics().report(CurPos.getLocation(), 661 | diag::ERR_VirtOverAsNonClassMember); 662 | return result; 663 | } 664 | 665 | ++CurPos; 666 | 667 | if (CurPos != tok::Delete) { 668 | --CurPos; 669 | tmp = parseFuncDecl(isClassMember); 670 | result.push_back(tmp.pop_back_val()); 671 | continue; 672 | } 673 | // Fall through 674 | 675 | case tok::Delete: { 676 | if (!isClassMember) { 677 | getDiagnostics().report(CurPos.getLocation(), 678 | diag::ERR_UnexpectedDestructorDecl); 679 | return result; 680 | } 681 | 682 | check(tok::Delete); 683 | check(tok::OpenParen); 684 | check(tok::CloseParen); 685 | 686 | if (CurPos != tok::BlockStart) { 687 | getDiagnostics().report(CurPos.getLocation(), 688 | diag::ERR_ExpectedDestructorBody); 689 | return result; 690 | } 691 | 692 | StmtAST *body = parseStmt(); 693 | ParameterList params; 694 | TypeAST *funcType = 695 | new FuncTypeAST(BuiltinTypeAST::get(TypeAST::TI_Void), params); 696 | result.push_back( 697 | new FuncDeclAST(loc, funcType, Name::Dtor, body, true, Tok)); 698 | continue; 699 | } 700 | 701 | case tok::Def: 702 | tmp = parseFuncDecl(isClassMember); 703 | result.push_back(tmp.pop_back_val()); 704 | continue; 705 | 706 | case tok::New: { 707 | if (!isClassMember) { 708 | getDiagnostics().report(CurPos.getLocation(), 709 | diag::ERR_UnexpectedConstructorDecl); 710 | return result; 711 | } 712 | 713 | ExprAST *superCtorCall = nullptr; 714 | ParameterList params; 715 | 716 | ++CurPos; 717 | check(tok::OpenParen); 718 | 719 | if (CurPos != tok::CloseParen) { 720 | for (;;) { 721 | Name *paramName = nullptr; 722 | 723 | if (CurPos == tok::Identifier) { 724 | paramName = CurPos->getIdentifier(); 725 | ++CurPos; 726 | 727 | // check for anonymouse parameter 728 | if (strcmp(paramName->Id, "_") == 0) { 729 | paramName = nullptr; 730 | } 731 | } else { 732 | check(tok::Identifier); 733 | } 734 | 735 | check(tok::Colon); 736 | 737 | TypeAST *type = parseType(); 738 | 739 | params.push_back(new ParameterAST(type, paramName)); 740 | 741 | if (CurPos != tok::Comma) { 742 | break; 743 | } 744 | 745 | ++CurPos; 746 | } 747 | } 748 | 749 | check(tok::CloseParen); 750 | 751 | if (CurPos == tok::Colon) { 752 | check(tok::Colon); 753 | 754 | if (CurPos != tok::Super) { 755 | getDiagnostics().report(CurPos.getLocation(), 756 | diag::ERR_ExpectedSuperAfterNew); 757 | return result; 758 | } else { 759 | ++CurPos; 760 | 761 | if (CurPos != tok::OpenParen) { 762 | getDiagnostics().report(CurPos.getLocation(), 763 | diag::ERR_ExpectedFuncArguments); 764 | return result; 765 | } 766 | 767 | ++CurPos; 768 | 769 | ExprList args; 770 | 771 | // Check for function call with 0 arguments 772 | if (CurPos != tok::CloseParen) { 773 | for (;;) { 774 | ExprAST *arg = parseAssignExpr(); 775 | args.push_back(arg); 776 | 777 | // If we have , then we should parse at least 1 more argument 778 | if (CurPos != tok::Comma) { 779 | break; 780 | } 781 | 782 | ++CurPos; 783 | } 784 | } 785 | 786 | check(tok::CloseParen); 787 | 788 | superCtorCall = new CallExprAST( 789 | loc, 790 | new MemberAccessExprAST(loc, new IdExprAST(loc, Name::Super), 791 | Name::Ctor), 792 | args); 793 | } 794 | } 795 | 796 | if (CurPos != tok::BlockStart) { 797 | getDiagnostics().report(CurPos.getLocation(), 798 | diag::ERR_ExpectedConstructorBody); 799 | return result; 800 | } 801 | 802 | StmtAST *body = parseStmt(); 803 | 804 | // Create function with such body: 805 | // { 806 | // opt super.__ctor(args); 807 | // body 808 | // } 809 | StmtList ctorBody; 810 | 811 | if (superCtorCall) { 812 | ctorBody.push_back(new ExprStmtAST(loc, superCtorCall)); 813 | } 814 | 815 | ctorBody.push_back(body); 816 | body = new BlockStmtAST(loc, ctorBody); 817 | TypeAST *funcType = 818 | new FuncTypeAST(BuiltinTypeAST::get(TypeAST::TI_Void), params); 819 | result.push_back( 820 | new FuncDeclAST(loc, funcType, Name::Ctor, body, true, tok::New)); 821 | continue; 822 | } 823 | 824 | case tok::Struct: { 825 | ++CurPos; 826 | Name *name = nullptr; 827 | 828 | if (CurPos == tok::Identifier) { 829 | name = CurPos->getIdentifier(); 830 | } 831 | 832 | check(tok::Identifier); 833 | 834 | check(tok::BlockStart); 835 | 836 | // Structures don't allow any declarations except variables 837 | while (CurPos != tok::BlockEnd && CurPos != tok::EndOfFile) { 838 | SymbolList tmp2 = parseDecl(true, true); 839 | tmp.append(tmp2.begin(), tmp2.end()); 840 | } 841 | 842 | check(tok::BlockEnd); 843 | result.push_back(new StructDeclAST(loc, name, tmp)); 844 | continue; 845 | } 846 | 847 | case tok::Class: { 848 | ++CurPos; 849 | Name *name = nullptr; 850 | TypeAST *baseType = nullptr; 851 | 852 | if (CurPos == tok::Identifier) { 853 | name = CurPos->getIdentifier(); 854 | } 855 | check(tok::Identifier); 856 | 857 | if (CurPos == tok::Extends) { 858 | check(tok::Extends); 859 | 860 | if (CurPos != tok::Identifier && CurPos != tok::Dot) { 861 | getDiagnostics().report(CurPos.getLocation(), 862 | diag::ERR_ExpectedQualifiedNameAsBase); 863 | return result; 864 | } 865 | 866 | baseType = parseType(); 867 | } 868 | 869 | check(tok::BlockStart); 870 | 871 | while (CurPos != tok::BlockEnd && CurPos != tok::EndOfFile) { 872 | SymbolList tmp2 = parseDecls(true); 873 | tmp.append(tmp2.begin(), tmp2.end()); 874 | } 875 | 876 | check(tok::BlockEnd); 877 | result.push_back(new ClassDeclAST(loc, name, baseType, tmp)); 878 | continue; 879 | } 880 | 881 | case tok::BlockEnd: 882 | case tok::EndOfFile: 883 | break; 884 | 885 | default: 886 | if (isClassMember) { 887 | SymbolList tmp2 = parseDecl(true, isClassMember); 888 | result.append(tmp2.begin(), tmp2.end()); 889 | continue; 890 | } 891 | break; 892 | } 893 | 894 | break; 895 | } 896 | 897 | return result; 898 | } 899 | 900 | /// module-decl ::= decls 901 | ModuleDeclAST *Parser::parseModule() { 902 | SymbolList decls = parseDecls(false); 903 | 904 | if (CurPos != tok::EndOfFile) { 905 | getDiagnostics().report(CurPos.getLocation(), diag::ERR_ExpectedEndOfFile); 906 | return nullptr; 907 | } 908 | 909 | return new ModuleDeclAST(getDiagnostics(), decls); 910 | } 911 | 912 | /// var-init 913 | /// ::= '=' assign-expr 914 | /// ::= '(' call-arguments ? ')' 915 | /// var-decl ::= identifier ':' type var-init? 916 | /// var-decls 917 | /// ::= var-decl 918 | /// ::= var-decls ',' var-decl 919 | /// decl-stmt ::= var-decls ';' 920 | SymbolList Parser::parseDecl(bool needSemicolon, bool isClassMember) { 921 | SymbolList result; 922 | 923 | for (;;) { 924 | llvm::SMLoc loc = CurPos.getLocation(); 925 | 926 | if (CurPos != tok::Identifier) { 927 | getDiagnostics().report(CurPos.getLocation(), diag::ERR_ExpectedIdentifierInDecl); 928 | } else { 929 | Name *name = CurPos->getIdentifier(); 930 | ExprAST *value = nullptr; 931 | 932 | ++CurPos; 933 | 934 | check(tok::Colon); 935 | 936 | TypeAST *type = parseType(); 937 | 938 | if (CurPos == tok::Assign) { 939 | if (isa(type) || isa(type)) { 940 | getDiagnostics().report(CurPos.getLocation(), 941 | diag::ERR_AggregateOrArrayInitializer); 942 | return result; 943 | } 944 | 945 | ++CurPos; 946 | value = parseAssignExpr(); 947 | } 948 | 949 | if (isa(type) && CurPos == tok::OpenParen) { 950 | ++CurPos; 951 | 952 | ExprList args; 953 | 954 | // Check for function call with 0 arguments 955 | if (CurPos != tok::CloseParen) { 956 | for (;;) { 957 | ExprAST *arg = parseAssignExpr(); 958 | args.push_back(arg); 959 | 960 | // If we have , then we should parse at least 1 more argument 961 | if (CurPos != tok::Comma) { 962 | break; 963 | } 964 | 965 | ++CurPos; 966 | } 967 | } 968 | 969 | check(tok::CloseParen); 970 | 971 | value = new CallExprAST( 972 | loc, 973 | new MemberAccessExprAST(loc, new IdExprAST(loc, name), Name::Ctor), 974 | args); 975 | } 976 | 977 | result.push_back(new VarDeclAST(loc, type, name, value, isClassMember)); 978 | 979 | if (CurPos != tok::Comma) { 980 | break; 981 | } 982 | 983 | ++CurPos; 984 | } 985 | } 986 | 987 | if (needSemicolon) { 988 | check(tok::Semicolon); 989 | } 990 | 991 | return result; 992 | } 993 | 994 | StmtAST *Parser::parseStmtAsBlock() { 995 | llvm::SMLoc loc = CurPos.getLocation(); 996 | StmtAST *result = parseStmt(); 997 | 998 | if (isa(result)) { 999 | return result; 1000 | } 1001 | 1002 | StmtList body; 1003 | body.push_back(result); 1004 | return new BlockStmtAST(loc, body); 1005 | } 1006 | 1007 | /// block-stmt ::= '{' stmt* '}' 1008 | /// for-init 1009 | /// ::= 'let' decl-stmt 1010 | /// ::= expr 1011 | /// for-stmt ::= 'for' for-init? ';' expr? ';' expr? block-stmt 1012 | /// stmt 1013 | /// ::= expr? ';' 1014 | /// ::= 'let' decl-stmt 1015 | /// ::= 'if' expr block-stmt ( 'else' block-stmt )? 1016 | /// ::= 'while' expr block-stmt 1017 | /// ::= for-stmt 1018 | /// ::= 'break' 1019 | /// ::= 'continue' 1020 | /// ::= 'return' expr? ';' 1021 | /// ::= block-stmt 1022 | StmtAST *Parser::parseStmt() { 1023 | StmtAST *result = nullptr; 1024 | llvm::SMLoc loc = CurPos.getLocation(); 1025 | 1026 | switch (CurPos->getKind()) { 1027 | case tok::Var: 1028 | ++CurPos; 1029 | return new DeclStmtAST(loc, parseDecl(true)); 1030 | 1031 | case tok::Plus: 1032 | case tok::Minus: 1033 | case tok::PlusPlus: 1034 | case tok::MinusMinus: 1035 | case tok::Tilda: 1036 | case tok::Not: 1037 | case tok::Identifier: 1038 | case tok::IntNumber: 1039 | case tok::FloatNumber: 1040 | case tok::Super: 1041 | case tok::This: 1042 | case tok::OpenParen: 1043 | case tok::Delete: 1044 | case tok::Mul: 1045 | case tok::BitAnd: 1046 | case tok::New: 1047 | case tok::Dot: { 1048 | ExprAST *expr = parseExpr(); 1049 | check(tok::Semicolon); 1050 | return new ExprStmtAST(loc, expr); 1051 | } 1052 | 1053 | case tok::If: { 1054 | check(tok::If); 1055 | ExprAST *expr = parseExpr(); 1056 | 1057 | if (CurPos != tok::BlockStart) { 1058 | check(tok::BlockStart); 1059 | } 1060 | 1061 | StmtAST *thenPart = parseStmtAsBlock(); 1062 | StmtAST *elsePart = nullptr; 1063 | 1064 | if (CurPos == tok::Else) { 1065 | ++CurPos; 1066 | 1067 | if (CurPos != tok::BlockStart) { 1068 | check(tok::BlockStart); 1069 | } 1070 | 1071 | elsePart = parseStmtAsBlock(); 1072 | } 1073 | 1074 | return new IfStmtAST(loc, expr, thenPart, elsePart); 1075 | } 1076 | 1077 | case tok::While: { 1078 | check(tok::While); 1079 | ExprAST *expr = parseExpr(); 1080 | 1081 | if (CurPos != tok::BlockStart) { 1082 | check(tok::BlockStart); 1083 | } 1084 | 1085 | result = parseStmtAsBlock(); 1086 | return new WhileStmtAST(loc, expr, result); 1087 | } 1088 | 1089 | case tok::For: { 1090 | check(tok::For); 1091 | 1092 | ExprAST *initExpr = nullptr, *condExpr = nullptr, *postExpr = nullptr; 1093 | SymbolList decls; 1094 | 1095 | if (CurPos != tok::Semicolon) { 1096 | if (CurPos == tok::Var) { 1097 | ++CurPos; 1098 | decls = parseDecl(true); 1099 | } else { 1100 | initExpr = parseExpr(); 1101 | check(tok::Semicolon); 1102 | } 1103 | } else { 1104 | check(tok::Semicolon); 1105 | } 1106 | 1107 | if (CurPos != tok::Semicolon) { 1108 | condExpr = parseExpr(); 1109 | } 1110 | 1111 | check(tok::Semicolon); 1112 | 1113 | if (CurPos != tok::BlockStart) { 1114 | postExpr = parseExpr(); 1115 | } 1116 | 1117 | if (CurPos != tok::BlockStart) { 1118 | check(tok::CloseParen); 1119 | } 1120 | 1121 | result = parseStmtAsBlock(); 1122 | return new ForStmtAST(loc, initExpr, decls, condExpr, postExpr, result); 1123 | } 1124 | 1125 | case tok::Break: 1126 | check(tok::Break); 1127 | check(tok::Semicolon); 1128 | return new BreakStmtAST(loc); 1129 | 1130 | case tok::Continue: 1131 | check(tok::Continue); 1132 | check(tok::Semicolon); 1133 | return new ContinueStmtAST(loc); 1134 | 1135 | case tok::Return: { 1136 | check(tok::Return); 1137 | 1138 | if (CurPos == tok::Semicolon) { 1139 | ++CurPos; 1140 | return new ReturnStmtAST(loc, nullptr); 1141 | } 1142 | 1143 | ExprAST *expr = parseExpr(); 1144 | check(tok::Semicolon); 1145 | return new ReturnStmtAST(loc, expr); 1146 | } 1147 | 1148 | case tok::BlockStart: { 1149 | StmtList stmts; 1150 | 1151 | ++CurPos; 1152 | 1153 | while (CurPos != tok::BlockEnd && CurPos != tok::EndOfFile) { 1154 | result = parseStmt(); 1155 | stmts.push_back(result); 1156 | } 1157 | 1158 | check(tok::BlockEnd); 1159 | return new BlockStmtAST(loc, stmts); 1160 | } 1161 | 1162 | case tok::Semicolon: 1163 | ++CurPos; 1164 | return new ExprStmtAST(loc, nullptr); 1165 | 1166 | default: 1167 | getDiagnostics().report(CurPos.getLocation(), diag::ERR_InvalidStatement); 1168 | return nullptr; 1169 | } 1170 | } 1171 | 1172 | SymbolAST *parseFuncProto(llvm::StringRef Proto) { 1173 | llvm::SourceMgr SrcMgr; 1174 | DiagnosticsEngine Diags(SrcMgr); 1175 | std::unique_ptr Buff = llvm::MemoryBuffer::getMemBuffer(Proto); 1176 | 1177 | // Tell SrcMgr about this buffer, which is what the 1178 | // parser will pick up. 1179 | SrcMgr.AddNewSourceBuffer(std::move(Buff), llvm::SMLoc()); 1180 | 1181 | Lexer Lex(SrcMgr, Diags); 1182 | Parser P(&Lex); 1183 | 1184 | return P.parseFuncProto(); 1185 | } 1186 | 1187 | } // namespace simple -------------------------------------------------------------------------------- /lib/CodeGen/Exprs.cpp: -------------------------------------------------------------------------------- 1 | #include "simple/AST/AST.h" 2 | 3 | using namespace llvm; 4 | 5 | namespace simple { 6 | 7 | /// Generate code for integral constant 8 | /// \param[in] value - constant's value 9 | ConstantInt* getConstInt(uint64_t value) { 10 | return ConstantInt::get(Type::getInt32Ty(getGlobalContext()), value, true); 11 | } 12 | 13 | /// Promote result of operation to bool type 14 | /// \param[in] val - value to convert 15 | /// \param[in] type - type to convert from 16 | /// \param[in] builder - IR builder for code generation pass 17 | Value* promoteToBool(Value* val, TypeAST* type, IRBuilder< >& builder) { 18 | if (type == BuiltinTypeAST::get(TypeAST::TI_Bool)) { 19 | // Value already has bool type return without changes 20 | return val; 21 | } 22 | 23 | if (type->isInt() || type->isChar()) { 24 | // Convert integral value to bool by comparison with 0 25 | return builder.CreateICmpNE(val, ConstantInt::get(type->getType(), 0)); 26 | } else if (isa(type) || type->isString()) { 27 | // Convert pointer or string value to bool by comparison with null 28 | return builder.CreateICmpNE(val, 29 | ConstantPointerNull::get((PointerType*)type->getType())); 30 | } else { 31 | assert(type->isFloat()); 32 | // Convert floating point value to bool by comparison with 0.0 33 | return builder.CreateFCmpUNE(val, ConstantFP::get( 34 | Type::getDoubleTy(getGlobalContext()), 0.0)); 35 | } 36 | } 37 | 38 | Value* ExprAST::getLValue(SLContext& ) { 39 | assert(0 && ""); 40 | return nullptr; 41 | } 42 | 43 | Value* IntExprAST::getRValue(SLContext& ) { 44 | return ConstantInt::get(ExprType->getType(), Val, true); 45 | } 46 | 47 | Value* FloatExprAST::getRValue(SLContext& ) { 48 | return ConstantFP::get(ExprType->getType(), Val); 49 | } 50 | 51 | Value* StringExprAST::getRValue(SLContext& Context) { 52 | // For string literal we need: 53 | // 1. Create global string; 54 | // 2. Create GetElementPtr instruction to get just created value from global 55 | // variable 56 | GlobalValue* val = Context.TheBuilder->CreateGlobalString(Val); 57 | std::vector< Value* > idx; 58 | 59 | idx.push_back(getConstInt(0)); 60 | idx.push_back(getConstInt(0)); 61 | 62 | return Context.TheBuilder->CreateInBoundsGEP(val->getValueType(), val, idx); 63 | } 64 | 65 | Value* ProxyExprAST::getRValue(SLContext& Context) { 66 | return OriginalExpr->getRValue(Context); 67 | } 68 | 69 | Value* NewExprAST::getRValue(SLContext& Context) { 70 | // We need to get size of type to allocate and patch old 0 value with actual 71 | // size 72 | uint64_t allocSize = Context.TheTarget->getTypeAllocSize(NewType->getType()); 73 | SizeExpr->Val = (int)allocSize; 74 | // Generate code for call expression 75 | Value* val = CallExpr->getRValue(Context); 76 | 77 | if (NeedCast) { 78 | // It wasn't constructor call and we should create cast to resulted type 79 | return Context.TheBuilder->CreateBitCast(val, ExprType->getType()); 80 | } 81 | 82 | return val; 83 | } 84 | 85 | Value* DeleteExprAST::getRValue(SLContext& Context) { 86 | Value* val = DeleteCall->getRValue(Context); 87 | return val; 88 | } 89 | 90 | Value* IdExprAST::getLValue(SLContext& Context) { 91 | return ThisSym->getValue(Context); 92 | } 93 | 94 | Value* IdExprAST::getRValue(SLContext& Context) { 95 | if (isa(ThisSym)) { 96 | // If it's function we should generate type for it 97 | return ThisSym->getValue(Context); 98 | } 99 | 100 | // For variable we should generate load instruction 101 | return Context.TheBuilder->CreateLoad( 102 | ExprType->getType(), 103 | ThisSym->getValue(Context), 104 | StringRef(Val->Id, Val->Length) 105 | ); 106 | } 107 | 108 | Value* IndexExprAST::getLValue(SLContext& Context) { 109 | // We have 2 different implementations for array and pointer 110 | if (isa(Left->ExprType)) { 111 | // We should get array as lvalue 112 | Value* val = Left->getLValue(Context); 113 | Value* index = Right->getRValue(Context); 114 | 115 | std::vector< Value* > idx; 116 | 117 | idx.push_back(getConstInt(0)); 118 | idx.push_back(index); 119 | 120 | return Context.TheBuilder->CreateInBoundsGEP(Left->ExprType->getType(), val, idx); 121 | } else { 122 | // We should get pointer as rvalue 123 | Value* val = Left->getRValue(Context); 124 | Value* index = Right->getRValue(Context); 125 | 126 | std::vector< Value* > idx; 127 | 128 | idx.push_back(index); 129 | 130 | return Context.TheBuilder->CreateInBoundsGEP(ExprType->getType(), val, idx); 131 | } 132 | } 133 | 134 | Value* IndexExprAST::getRValue(SLContext& Context) { 135 | Value* val = getLValue(Context); 136 | return Context.TheBuilder->CreateLoad(ExprType->getType(), val); 137 | } 138 | 139 | /// Convert pointer to class to pointer to base class 140 | /// \param[in] Context - code generator context 141 | /// \param[in] val - pointer to convert 142 | /// \param[in] var - symbol of aggregate to convert to 143 | /// \param[in] agg - symbol of aggregate to convert from 144 | /// \param[in] canBeNull - true - value \c val can contain null 145 | Value* convertToBase(SLContext& Context, Value* val, SymbolAST* var, 146 | SymbolAST* agg, bool canBeNull) { 147 | ClassDeclAST* thisDecl = (ClassDeclAST*)agg; 148 | SymbolAST* baseDecl = thisDecl->BaseClass->getSymbol(); 149 | bool baseHasVTable = false; 150 | 151 | // If base class is class and not struct then it can have VTable 152 | if (isa(baseDecl)) { 153 | ClassDeclAST* baseClassDecl = (ClassDeclAST*)baseDecl; 154 | baseHasVTable = baseClassDecl->VTbl != nullptr; 155 | } 156 | 157 | // If base class don't have VTable and this class has then we should make 158 | // adjustments 159 | if (thisDecl->VTbl && baseHasVTable == false) { 160 | // If value can be 0 then we should have some checking before cast 161 | if (canBeNull) { 162 | // Right now val is the pointer to some derived class. We should check 163 | // it for null for safe cast 164 | Value* tmp = ConstantPointerNull::get((PointerType*)val->getType()); 165 | tmp = Context.TheBuilder->CreateICmpNE(val, tmp); 166 | 167 | BasicBlock* thenBlock = BasicBlock::Create(getGlobalContext(), "then", 168 | Context.TheFunction); 169 | BasicBlock* elseBlock = BasicBlock::Create(getGlobalContext(), "else"); 170 | BasicBlock* contBlock = BasicBlock::Create(getGlobalContext(), "ifcont"); 171 | 172 | tmp = Context.TheBuilder->CreateCondBr(tmp, thenBlock, elseBlock); 173 | Context.TheBuilder->SetInsertPoint(thenBlock); 174 | 175 | // 1. Adjust pointer and skip VTable slot 176 | val = Context.TheBuilder->CreateGEP( 177 | Type::getInt8Ty(getGlobalContext()), 178 | val, 179 | getConstInt( 180 | Context.TheTarget->getTypeAllocSize( 181 | PointerType::get( 182 | getGlobalContext(), 183 | getSLContext().TheTarget->getProgramAddressSpace() 184 | ) 185 | ) 186 | ) 187 | ); 188 | 189 | // 2. Get real address of base class 190 | if (var != baseDecl) { 191 | // It has 1 more nesting level. Check it 192 | val = convertToBase(Context, val, var, baseDecl, canBeNull); 193 | } 194 | 195 | thenBlock = Context.TheBuilder->GetInsertBlock(); 196 | Context.TheBuilder->CreateBr(contBlock); 197 | 198 | // Note: elseBlock contain only jump and no code 199 | Context.TheFunction->getBasicBlockList().push_back(elseBlock); 200 | Context.TheBuilder->SetInsertPoint(elseBlock); 201 | 202 | Context.TheBuilder->CreateBr(contBlock); 203 | 204 | Context.TheFunction->getBasicBlockList().push_back(contBlock); 205 | Context.TheBuilder->SetInsertPoint(contBlock); 206 | 207 | // Create PHI node with resulted value 208 | PHINode* PN = Context.TheBuilder->CreatePHI(val->getType(), 2); 209 | 210 | PN->addIncoming(val, thenBlock); 211 | PN->addIncoming(ConstantPointerNull::get((PointerType*)val->getType()), 212 | elseBlock); 213 | 214 | return PN; 215 | } else { 216 | // Value can't be 0. We don't need any checking 217 | 218 | // 1. Adjust pointer and skip VTable slot 219 | val = Context.TheBuilder->CreateGEP( 220 | Type::getInt8Ty(getGlobalContext()), 221 | val, 222 | getConstInt( 223 | Context.TheTarget->getTypeAllocSize( 224 | PointerType::get( 225 | getGlobalContext(), 226 | getSLContext().TheTarget->getProgramAddressSpace() 227 | ) 228 | ) 229 | ) 230 | ); 231 | 232 | // 2. Get real address of base class 233 | if (var != baseDecl) { 234 | // It has 1 more nesting level. Check it 235 | return convertToBase(Context, val, var, baseDecl, canBeNull); 236 | } 237 | 238 | return val; 239 | } 240 | } else { 241 | // There is no VTable or both types have VTables 242 | 243 | if (var == baseDecl) { 244 | return val; 245 | } 246 | 247 | // It has 1 more nesting level. Check it 248 | return convertToBase(Context, val, var, baseDecl, canBeNull); 249 | } 250 | } 251 | 252 | Value* MemberAccessExprAST::getLValue(SLContext& Context) { 253 | // For function simply return value 254 | if (isa(ExprType)) { 255 | return ThisSym->getValue(Context); 256 | } 257 | 258 | // Generate lvalue for this 259 | Value* val = Val->getLValue(Context); 260 | 261 | // If symbol's parent not found aggregate then we need convert it to base 262 | // class/struct 263 | if (ThisSym->Parent != ThisAggr) { 264 | val = convertToBase(Context, val, ThisSym->Parent, ThisAggr, false); 265 | } 266 | 267 | // Generate code for member's offset 268 | Value* index = getConstInt(((VarDeclAST*)ThisSym)->OffsetOf); 269 | 270 | std::vector< Value* > idx; 271 | 272 | idx.push_back(getConstInt(0)); 273 | idx.push_back(index); 274 | 275 | // Generate GetElementPtr for needed value 276 | return Context.TheBuilder->CreateGEP(ThisSym->Parent->getType()->getType(), val, idx); 277 | } 278 | 279 | Value* MemberAccessExprAST::getRValue(SLContext& Context) { 280 | // Generate lvalue for this 281 | Value* val = getLValue(Context); 282 | 283 | // For function simply return value 284 | if (isa(ExprType)) { 285 | return val; 286 | } 287 | 288 | // For rvalue we always need to load just generated value 289 | return Context.TheBuilder->CreateLoad(ExprType->getType(), val); 290 | } 291 | 292 | Value* PointerAccessExprAST::getLValue(SLContext& Context) { 293 | assert(0 && "PointerAccessExprAST::getLValue should never be reached"); 294 | return nullptr; 295 | } 296 | 297 | Value* PointerAccessExprAST::getRValue(SLContext& Context) { 298 | assert(0 && "PointerAccessExprAST::getRValue should never be reached"); 299 | return nullptr; 300 | } 301 | 302 | Value* DerefExprAST::getLValue(SLContext& Context) { 303 | // Check is it lvalue or not 304 | if (Val->isLValue()) { 305 | Value* val = Val->getLValue(Context); 306 | return Context.TheBuilder->CreateLoad( 307 | PointerType::get( 308 | getGlobalContext(), 309 | Context.TheTarget->getProgramAddressSpace() 310 | ), 311 | val 312 | ); 313 | } else { 314 | // Special case for function's call and binary expression 315 | return Val->getRValue(Context); 316 | } 317 | } 318 | 319 | Value* DerefExprAST::getRValue(SLContext& Context) { 320 | Value* val = getLValue(Context); 321 | 322 | // If it's function return it's value 323 | if (isa(ExprType)) { 324 | return val; 325 | } 326 | 327 | // For rvalue we always need to generate load 328 | return Context.TheBuilder->CreateLoad(ExprType->getType(), val); 329 | } 330 | 331 | Value* AddressOfExprAST::getRValue(SLContext& Context) { 332 | // For address expression rvalue use lvalue of nested expression 333 | // Note: We can't have lvalue 334 | return Val->getLValue(Context); 335 | } 336 | 337 | Value* CastExprAST::getRValue(SLContext& Context) { 338 | // Check convert to int first 339 | if (ExprType->isInt()) { 340 | if (Val->ExprType->isBool() || Val->ExprType->isChar()) { 341 | // If old expression type is bool then extend value with 0 342 | return Context.TheBuilder->CreateZExt(Val->getRValue(Context), 343 | ExprType->getType()); 344 | } 345 | 346 | assert(Val->ExprType->isFloat()); 347 | // It's floating point value, convert it to int 348 | return Context.TheBuilder->CreateFPToSI(Val->getRValue(Context), 349 | ExprType->getType()); 350 | } 351 | 352 | // Check convert to bool now 353 | if (ExprType->isBool()) { 354 | // We should promote old value to bool type 355 | return promoteToBool(Val->getRValue(Context), Val->ExprType, 356 | *Context.TheBuilder); 357 | // Check for conversion to char 358 | } else if (ExprType->isChar()) { 359 | // If it's bool then extend it 360 | if (Val->ExprType->isBool()) { 361 | return Context.TheBuilder->CreateZExt(Val->getRValue(Context), 362 | ExprType->getType()); 363 | } 364 | 365 | assert(Val->ExprType->isInt()); 366 | // Truncate integral value 367 | return Context.TheBuilder->CreateTrunc(Val->getRValue(Context), 368 | ExprType->getType()); 369 | // Check for conversion to string 370 | } else if (ExprType->isString()) { 371 | if (isa(Val->ExprType)) { 372 | Value* val = Val->getLValue(Context); 373 | Value* tmp = getConstInt(0); 374 | 375 | std::vector< Value* > idx; 376 | 377 | idx.push_back(tmp); 378 | idx.push_back(tmp); 379 | 380 | if (isa(val)) { 381 | AllocaInst *alloca = (AllocaInst*)val; 382 | 383 | return Context.TheBuilder->CreateGEP(alloca->getAllocatedType(), val, idx); 384 | } else { 385 | assert(0); 386 | } 387 | } else { 388 | Value* val = Val->getRValue(Context); 389 | // Generate cast 390 | return Context.TheBuilder->CreateBitCast(val, ExprType->getType()); 391 | } 392 | // Check for conversion to pointer 393 | } else if (isa(ExprType)) { 394 | // If converted expression is pointer too then check it 395 | if (isa(Val->ExprType)) { 396 | // Generate rvalue expression 397 | Value* val = Val->getRValue(Context); 398 | 399 | TypeAST* next1 = ((PointerTypeAST*)ExprType)->Next; 400 | TypeAST* next2 = ((PointerTypeAST*)Val->ExprType)->Next; 401 | 402 | // We have special case for aggregates and their base classes 403 | if (next1->isAggregate() && next1->isBaseOf(next2)) { 404 | SymbolAST* s1 = next1->getSymbol(); 405 | SymbolAST* s2 = next2->getSymbol(); 406 | 407 | return convertToBase(Context, val, s1, s2, Val->canBeNull()); 408 | } 409 | 410 | return val; 411 | } else if (isa(Val->ExprType)) { 412 | Value* val = Val->getLValue(Context); 413 | Value* tmp = getConstInt(0); 414 | 415 | std::vector< Value* > idx; 416 | 417 | idx.push_back(tmp); 418 | idx.push_back(tmp); 419 | 420 | if (isa(val)) { 421 | AllocaInst *alloca = (AllocaInst*)val; 422 | 423 | tmp = Context.TheBuilder->CreateGEP(alloca->getAllocatedType(), val, idx); 424 | } else { 425 | assert(0); 426 | } 427 | 428 | PointerTypeAST* ptrType = (PointerTypeAST*)ExprType; 429 | 430 | if (ptrType->Next->isVoid()) { 431 | tmp = Context.TheBuilder->CreateBitCast(tmp, ptrType->getType()); 432 | } 433 | 434 | return tmp; 435 | } else { 436 | Value* val = Val->getRValue(Context); 437 | // Generate cast 438 | return Context.TheBuilder->CreateBitCast(val, ExprType->getType()); 439 | } 440 | } else if (Val->ExprType->isInt() || Val->ExprType->isChar()) { 441 | // It's char or int value, convert it to float 442 | return Context.TheBuilder->CreateSIToFP(Val->getRValue(Context), 443 | ExprType->getType()); 444 | } else if (Val->ExprType->isBool()) { 445 | // It's bool value, convert it to float 446 | return Context.TheBuilder->CreateUIToFP(Val->getRValue(Context), 447 | ExprType->getType()); 448 | } 449 | 450 | assert(0 && "should never be reached"); 451 | return nullptr; 452 | } 453 | 454 | Value* UnaryExprAST::getRValue(SLContext& Context) { 455 | assert(Op == tok::PlusPlus || Op == tok::MinusMinus); 456 | assert(isa(Val) || isa(Val) || ExprType->isString()); 457 | // Generate code for lvalue 458 | Value* val = Val->getLValue(Context); 459 | // Generate load with add 1 or add -1 460 | Value* res = Context.TheBuilder->CreateLoad(ExprType->getType(), val); 461 | Value* tmp = getConstInt((Op == tok::PlusPlus) ? 1ULL : ~0ULL); 462 | 463 | if (isa(ExprType) || ExprType->isString()) { 464 | Type *resType; 465 | 466 | if (isa(ExprType)) { 467 | PointerTypeAST *ptrType = (PointerTypeAST*)ExprType; 468 | 469 | if (ptrType->Next->isVoid()) { 470 | resType = Type::getInt8Ty(getGlobalContext()); 471 | } else { 472 | resType = ptrType->Next->getType(); 473 | } 474 | } else { 475 | resType = Type::getInt8Ty(getGlobalContext()); 476 | } 477 | 478 | // Special case for pointers 479 | res = Context.TheBuilder->CreateGEP(resType, res, tmp); 480 | } else { 481 | res = Context.TheBuilder->CreateAdd(res, tmp); 482 | } 483 | 484 | // Store resulted value back 485 | Context.TheBuilder->CreateStore(res, val); 486 | return res; 487 | } 488 | 489 | Value* BinaryExprAST::getRValue(SLContext& Context) { 490 | // Check all special case binary expressions 1st 491 | 492 | // = operator 493 | if (Op == tok::Assign) { 494 | 495 | // Generate code for right operand of the expression 496 | Value* right; 497 | 498 | // We have special case for pointer 499 | if (isa(ExprType)) { 500 | // If it's integral constant 0 then we should convert it to null 501 | if (RightExpr->ExprType->isInt()) { 502 | right = ConstantPointerNull::get((PointerType*)ExprType->getType()); 503 | } else { 504 | // Generate rvalue otherwise 505 | right = RightExpr->getRValue(Context); 506 | } 507 | } else { 508 | // Generate rvalue 509 | right = RightExpr->getRValue(Context); 510 | } 511 | 512 | // Get address of a variable to hold result 513 | Value* res = LeftExpr->getLValue(Context); 514 | 515 | // Generate store to variable and return right operand 516 | Context.TheBuilder->CreateStore(right, res); 517 | return right; 518 | } 519 | 520 | // , operator 521 | if (Op == tok::Comma) { 522 | // Generate code for left and right operands 523 | LeftExpr->getRValue(Context); 524 | Value* rhs = RightExpr->getRValue(Context); 525 | // Return result of right operand 526 | return rhs; 527 | } 528 | 529 | // postfix versions of ++ and -- operators 530 | if (Op == tok::PlusPlus || Op == tok::MinusMinus) { 531 | // Get address of a variable and generate load instruction 532 | Value* var = LeftExpr->getLValue(Context); 533 | Value* val = nullptr; 534 | 535 | if (isa(LeftExpr) || isa(LeftExpr)) { 536 | // Special case for indexing and member access expressions, because we 537 | // don't want to generate GetElementPtr instruction twice 538 | val = Context.TheBuilder->CreateLoad(ExprType->getType(), var); 539 | } else { 540 | val = LeftExpr->getRValue(Context); 541 | } 542 | 543 | if (!LeftExpr->ExprType->isInt()) { 544 | // Special case for pointer types. We should generate GetElementPtr 545 | // instruction 546 | Value* tmp = getConstInt((Op == tok::PlusPlus) ? 1ULL : ~0ULL); 547 | Type *resType; 548 | 549 | if (isa(ExprType)) { 550 | PointerTypeAST *ptrType = (PointerTypeAST*)ExprType; 551 | 552 | if (ptrType->Next->isVoid()) { 553 | resType = Type::getInt8Ty(getGlobalContext()); 554 | } else { 555 | resType = ptrType->Next->getType(); 556 | } 557 | } else { 558 | resType = Type::getInt8Ty(getGlobalContext()); 559 | } 560 | 561 | tmp = Context.TheBuilder->CreateGEP(resType, val, tmp); 562 | // Store result and return old value 563 | Context.TheBuilder->CreateStore(tmp, var); 564 | return val; 565 | } else { 566 | if (Op == tok::PlusPlus) { 567 | // Create integral constant 1 and add it to loaded variable 568 | Value* tmp = getConstInt(1); 569 | tmp = Context.TheBuilder->CreateAdd(val, tmp, "inctmp"); 570 | // Store result and return old value 571 | Context.TheBuilder->CreateStore(tmp, var); 572 | return val; 573 | } else { 574 | // Create integral constant -1 and add it to loaded variable 575 | Value* tmp = getConstInt(~0ULL); 576 | tmp = Context.TheBuilder->CreateAdd(val, tmp, "dectmp"); 577 | // Store result and return old value 578 | Context.TheBuilder->CreateStore(tmp, var); 579 | return val; 580 | } 581 | } 582 | } 583 | 584 | // || operator 585 | if (Op == tok::LogOr) { 586 | //Pseudo code for || operator 587 | 588 | //if (bool result = (left != 0)) 589 | // return result; 590 | //else 591 | // return (right != 0); 592 | 593 | // Generate code for left operand 594 | Value* lhs = LeftExpr->getRValue(Context); 595 | // Promote just generated result to bool 596 | lhs = promoteToBool(lhs, LeftExpr->ExprType, *Context.TheBuilder); 597 | 598 | // Get blocks for just generated value, result and false branches 599 | BasicBlock* condBB = Context.TheBuilder->GetInsertBlock(); 600 | BasicBlock* resultBB = BasicBlock::Create(getGlobalContext(), "result"); 601 | BasicBlock* falseBB = BasicBlock::Create(getGlobalContext(), "false"); 602 | 603 | // Create conditional jump to result or false branches based on result of 604 | // left operand 605 | Context.TheBuilder->CreateCondBr(lhs, resultBB, falseBB); 606 | 607 | // Add false branch to the end of the function and set it as insertion point 608 | Context.TheFunction->getBasicBlockList().push_back(falseBB); 609 | Context.TheBuilder->SetInsertPoint(falseBB); 610 | // Generate code for right operand 611 | Value* rhs = RightExpr->getRValue(Context); 612 | // Update false branch if it was changed by right operand 613 | falseBB = Context.TheBuilder->GetInsertBlock(); 614 | // Promote value of right operand to bool 615 | rhs = promoteToBool(rhs, RightExpr->ExprType, *Context.TheBuilder); 616 | // Create jump to result branch 617 | Context.TheBuilder->CreateBr(resultBB); 618 | 619 | // Add result branch to the end of the function and set it as insertion point 620 | Context.TheFunction->getBasicBlockList().push_back(resultBB); 621 | Context.TheBuilder->SetInsertPoint(resultBB); 622 | 623 | // Now we need to create PHI node which should have result from conditional 624 | // branch or false branch 625 | PHINode* PN = Context.TheBuilder->CreatePHI(Type::getInt1Ty(getGlobalContext()), 2); 626 | 627 | PN->addIncoming(lhs, condBB); 628 | PN->addIncoming(rhs, falseBB); 629 | 630 | return PN; 631 | } 632 | 633 | // && operator 634 | if (Op == tok::LogAnd) { 635 | //Pseudo code for && operator 636 | 637 | //if (left != 0 && right != 0) 638 | // return true; 639 | //else 640 | // return false; 641 | 642 | // Generate code for left operand 643 | Value* lhs = LeftExpr->getRValue(Context); 644 | // Promote just generated result to bool 645 | lhs = promoteToBool(lhs, LeftExpr->ExprType, *Context.TheBuilder); 646 | 647 | // Get blocks for just generated value, result and true branches 648 | BasicBlock* condBB = Context.TheBuilder->GetInsertBlock(); 649 | BasicBlock* resultBB = BasicBlock::Create(getGlobalContext(), "result"); 650 | BasicBlock* trueBB = BasicBlock::Create(getGlobalContext(), "true"); 651 | 652 | // Create conditional jump to true or result branches based on result of 653 | // left operand 654 | Context.TheBuilder->CreateCondBr(lhs, trueBB, resultBB); 655 | 656 | // Add false branch to the end of the function and set it as insertion point 657 | Context.TheFunction->getBasicBlockList().push_back(trueBB); 658 | Context.TheBuilder->SetInsertPoint(trueBB); 659 | // Generate code for right operand 660 | Value* rhs = RightExpr->getRValue(Context); 661 | // Update true branch if it was changed by right operand 662 | trueBB = Context.TheBuilder->GetInsertBlock(); 663 | // Promote value of right operand to bool 664 | rhs = promoteToBool(rhs, RightExpr->ExprType, *Context.TheBuilder); 665 | // Create jump to result branch 666 | Context.TheBuilder->CreateBr(resultBB); 667 | 668 | // Add result branch to the end of the function and set it as insertion point 669 | Context.TheFunction->getBasicBlockList().push_back(resultBB); 670 | Context.TheBuilder->SetInsertPoint(resultBB); 671 | 672 | // Now we need to create PHI node which should have result from conditional 673 | // branch or true branch 674 | PHINode* PN = Context.TheBuilder->CreatePHI(Type::getInt1Ty(getGlobalContext()), 2); 675 | 676 | PN->addIncoming(lhs, condBB); 677 | PN->addIncoming(rhs, trueBB); 678 | 679 | return PN; 680 | } 681 | 682 | // Special case for +/- on pointers 683 | if (isa(ExprType)) { 684 | Value* ptr = LeftExpr->getRValue(Context); 685 | Value* index = RightExpr->getRValue(Context); 686 | 687 | if (Op == tok::Minus) { 688 | index = Context.TheBuilder->CreateSub(getConstInt(0), index); 689 | } 690 | 691 | PointerTypeAST *ptrType = (PointerTypeAST*)ExprType; 692 | Type *resType = ptrType->Next->isVoid() 693 | ? Type::getInt8Ty(getGlobalContext()) 694 | : ptrType->Next->getType(); 695 | 696 | return Context.TheBuilder->CreateGEP(resType, ptr, index); 697 | } 698 | 699 | // It's regular binary operator 700 | 701 | // Generate code for left and right operands 702 | Value* lhs = LeftExpr->getRValue(Context); 703 | Value* rhs = RightExpr->getRValue(Context); 704 | 705 | // Check type of left operand 706 | if (LeftExpr->ExprType == BuiltinTypeAST::get(TypeAST::TI_Int)) { 707 | // Generate code for result value based on operator 708 | switch (Op) { 709 | case tok::Plus: return Context.TheBuilder->CreateAdd(lhs, rhs, "addtmp"); 710 | case tok::Minus: return Context.TheBuilder->CreateSub(lhs, rhs, "subtmp"); 711 | case tok::Mul: return Context.TheBuilder->CreateMul(lhs, rhs, "multmp"); 712 | case tok::Div: return Context.TheBuilder->CreateSDiv(lhs, rhs, "divtmp"); 713 | case tok::Mod: return Context.TheBuilder->CreateSRem(lhs, rhs, "remtmp"); 714 | case tok::BitOr: return Context.TheBuilder->CreateOr(lhs, rhs, "ortmp"); 715 | case tok::BitAnd: return Context.TheBuilder->CreateAnd(lhs, rhs, "andtmp"); 716 | case tok::BitXor: return Context.TheBuilder->CreateXor(lhs, rhs, "xortmp"); 717 | case tok::LShift: return Context.TheBuilder->CreateShl(lhs, rhs, "shltmp"); 718 | case tok::RShift: return Context.TheBuilder->CreateAShr(lhs, rhs, "shrtmp"); 719 | case tok::Less: return Context.TheBuilder->CreateICmpSLT(lhs, rhs, "cmptmp"); 720 | case tok::Greater: return Context.TheBuilder->CreateICmpSGT(lhs, rhs, "cmptmp"); 721 | case tok::LessEqual: return Context.TheBuilder->CreateICmpSLE(lhs, rhs, "cmptmp"); 722 | case tok::GreaterEqual: return Context.TheBuilder->CreateICmpSGE(lhs, rhs, "cmptmp"); 723 | case tok::Equal: return Context.TheBuilder->CreateICmpEQ(lhs, rhs, "cmptmp"); 724 | case tok::NotEqual: return Context.TheBuilder->CreateICmpNE(lhs, rhs, "cmptmp"); 725 | default: assert(0 && "Invalid integral binary operator"); return nullptr; 726 | } 727 | } 728 | 729 | // Generate code for result value based on operator 730 | switch (Op) { 731 | case tok::Plus: return Context.TheBuilder->CreateFAdd(lhs, rhs, "addtmp"); 732 | case tok::Minus: return Context.TheBuilder->CreateFSub(lhs, rhs, "subtmp"); 733 | case tok::Mul: return Context.TheBuilder->CreateFMul(lhs, rhs, "multmp"); 734 | case tok::Div: return Context.TheBuilder->CreateFDiv(lhs, rhs, "divtmp"); 735 | case tok::Mod: return Context.TheBuilder->CreateFRem(lhs, rhs, "remtmp"); 736 | case tok::Less: return Context.TheBuilder->CreateFCmpULT(lhs, rhs, "cmptmp"); 737 | case tok::Greater: return Context.TheBuilder->CreateFCmpUGT(lhs, rhs, "cmptmp"); 738 | case tok::LessEqual: return Context.TheBuilder->CreateFCmpULE(lhs, rhs, "cmptmp"); 739 | case tok::GreaterEqual: return Context.TheBuilder->CreateFCmpUGE(lhs, rhs, "cmptmp"); 740 | case tok::Equal: return Context.TheBuilder->CreateFCmpUEQ(lhs, rhs, "cmptmp"); 741 | case tok::NotEqual: return Context.TheBuilder->CreateFCmpUNE(lhs, rhs, "cmptmp"); 742 | default: assert(0 && "Invalid floating point binary operator"); return nullptr; 743 | } 744 | } 745 | 746 | /// Generate code for conditional expression 747 | /// \param[in] Context - code generation context 748 | /// \param[in] Cond - condition 749 | /// \param[in] IfExpr - if part 750 | /// \param[in] ElseExpr - else part 751 | /// \param[in] isLValue - true - if we need generate code for lvalue 752 | Value* generateCondExpr(SLContext& Context, ExprAST* Cond, ExprAST* IfExpr, 753 | ExprAST* ElseExpr, bool isLValue) { 754 | // Generate code for conditional part 755 | Value* cond = Cond->getRValue(Context); 756 | // Promote just generated value to bool 757 | cond = promoteToBool(cond, Cond->ExprType, *Context.TheBuilder); 758 | 759 | // Get blocks for then, else and continue branches 760 | BasicBlock* thenBB = BasicBlock::Create(getGlobalContext(), "then", 761 | Context.TheFunction); 762 | BasicBlock* elseBB = BasicBlock::Create(getGlobalContext(), "else"); 763 | BasicBlock* mergeBB = BasicBlock::Create(getGlobalContext(), "ifcont"); 764 | 765 | // Create conditional jump to then or else branches based on result of 766 | // conditional part 767 | Context.TheBuilder->CreateCondBr(cond, thenBB, elseBB); 768 | // Set insert point to a then branch 769 | Context.TheBuilder->SetInsertPoint(thenBB); 770 | 771 | // Generate code for then part 772 | Value* thenValue; 773 | 774 | // For lvalue we should generate lvalue 775 | if (isLValue) { 776 | thenValue = IfExpr->getLValue(Context); 777 | } else { 778 | thenValue = IfExpr->getRValue(Context); 779 | } 780 | 781 | // Create jump to continue branch and update then part if it was changed 782 | Context.TheBuilder->CreateBr(mergeBB); 783 | thenBB = Context.TheBuilder->GetInsertBlock(); 784 | 785 | // Add else branch to the end of the function and set it as insertion point 786 | Context.TheFunction->getBasicBlockList().push_back(elseBB); 787 | Context.TheBuilder->SetInsertPoint(elseBB); 788 | 789 | Value* elseValue; 790 | 791 | // For lvalue we should generate lvalue 792 | if (isLValue) { 793 | elseValue = ElseExpr->getLValue(Context); 794 | } else { 795 | elseValue = ElseExpr->getRValue(Context); 796 | } 797 | 798 | // Create jump to continue branch and update else part if it was changed 799 | Context.TheBuilder->CreateBr(mergeBB); 800 | elseBB = Context.TheBuilder->GetInsertBlock(); 801 | 802 | // Add continue branch to the end of the function and set it as insertion 803 | // point 804 | Context.TheFunction->getBasicBlockList().push_back(mergeBB); 805 | Context.TheBuilder->SetInsertPoint(mergeBB); 806 | 807 | // For void type we are done 808 | if (!IfExpr->ExprType || IfExpr->ExprType->isVoid()) { 809 | return nullptr; 810 | } 811 | 812 | // Now we need to create PHI node which should have result from then or else 813 | // branches 814 | PHINode* PN; 815 | 816 | if (isLValue) { 817 | // For lvalue we get pointer to original expression's type 818 | PN = Context.TheBuilder->CreatePHI( 819 | PointerType::get( 820 | getGlobalContext(), 821 | Context.TheTarget->getProgramAddressSpace() 822 | ), 823 | 2 824 | ); 825 | } else { 826 | PN = Context.TheBuilder->CreatePHI(IfExpr->ExprType->getType(), 2); 827 | } 828 | 829 | PN->addIncoming(thenValue, thenBB); 830 | PN->addIncoming(elseValue, elseBB); 831 | 832 | return PN; 833 | } 834 | 835 | Value* CondExprAST::getLValue(SLContext& Context) { 836 | return generateCondExpr(Context, Cond, IfExpr, ElseExpr, true); 837 | } 838 | 839 | Value* CondExprAST::getRValue(SLContext& Context) { 840 | return generateCondExpr(Context, Cond, IfExpr, ElseExpr, false); 841 | } 842 | 843 | Value* CallExprAST::getRValue(SLContext& Context) { 844 | // Generate code for callee (actually only get function's address) 845 | Value* callee = nullptr; 846 | std::vector< Value* > args; 847 | ExprList::iterator it = Args.begin(); 848 | Value* forcedReturn = nullptr; 849 | 850 | // Check is it virtual call or not 851 | assert(isa(CallFunc)); 852 | FuncDeclAST* funcDecl = (FuncDeclAST*)CallFunc; 853 | Type* funcRawType = CallFunc->getType()->getType(); 854 | assert(isa(funcRawType)); 855 | FunctionType* funcType = static_cast(funcRawType); 856 | 857 | if (funcDecl->isVirtual() || funcDecl->isOverride()) { 858 | // It's virtual function perform virtual call 859 | assert(isa(Callee)); 860 | MemberAccessExprAST* memAccess = (MemberAccessExprAST*)Callee; 861 | 862 | // We should check is Callee pointer or not 863 | if (isa(memAccess->Val)) { 864 | // It's dereference. Now we should check was it super or not. Because we 865 | // should make sure that super not use virtual calls 866 | DerefExprAST* derefExpr = (DerefExprAST*)memAccess->Val; 867 | 868 | if ((isa(derefExpr->Val) && 869 | ((IdExprAST*)derefExpr->Val)->Val == Name::Super)) { 870 | // It's call with super as this parameter. Call it as non virtual function 871 | callee = CallFunc->getValue(Context); 872 | } else { 873 | // It's virtual function. Make virtual call 874 | 875 | // Get this pointer 876 | callee = memAccess->Val->getLValue(Context); 877 | 878 | // Virtual functions table is always 1st member. But we still need cast 879 | // this to class with function 880 | PointerType* ptrType = PointerType::get( 881 | getGlobalContext(), 882 | getSLContext().TheTarget->getProgramAddressSpace() 883 | ); 884 | 885 | // Load virtual functions table 886 | callee = Context.TheBuilder->CreateLoad(ptrType, callee); 887 | // Get function from virtual functions table by it's index 888 | callee = Context.TheBuilder->CreateGEP( 889 | ptrType, 890 | callee, 891 | getConstInt(((FuncDeclAST*)CallFunc)->OffsetOf) 892 | ); 893 | callee = Context.TheBuilder->CreateLoad(ptrType, callee); 894 | } 895 | } else { 896 | if (memAccess->ForceThis) { 897 | // It's virtual function. Make virtual call 898 | 899 | // Get this pointer 900 | callee = memAccess->Val->getRValue(Context); 901 | 902 | // Virtual functions table is always 1st member. But we still need cast 903 | // this to class with function 904 | PointerType* ptrType = PointerType::get( 905 | getGlobalContext(), 906 | getSLContext().TheTarget->getProgramAddressSpace() 907 | ); 908 | 909 | // Load virtual functions table 910 | callee = Context.TheBuilder->CreateLoad(ptrType, callee); 911 | // Get function from virtual functions table by it's index 912 | callee = Context.TheBuilder->CreateGEP( 913 | ptrType, 914 | callee, 915 | getConstInt(((FuncDeclAST*)CallFunc)->OffsetOf) 916 | ); 917 | callee = Context.TheBuilder->CreateLoad(ptrType, callee); 918 | } else { 919 | // It's not pointer. Use regular function call 920 | callee = CallFunc->getValue(Context); 921 | } 922 | } 923 | } else { 924 | // It's regular function call 925 | callee = CallFunc->getValue(Context); 926 | } 927 | 928 | // We have special case for class member function 929 | if (isa(Callee)) { 930 | MemberAccessExprAST* memAccess = (MemberAccessExprAST*)Callee; 931 | // Check for forced this 932 | if (!memAccess->ForceThis) { 933 | // It's not forced this. Get lvalue from left part of member access 934 | // expression 935 | Value* val = (*it)->getLValue(Context); 936 | MemberAccessExprAST* memAccess = (MemberAccessExprAST*)Callee; 937 | 938 | // Perform conversion from derived class to base class if needed 939 | if (memAccess->ThisSym->Parent != memAccess->ThisAggr) { 940 | val = convertToBase(Context, val, memAccess->ThisSym->Parent, 941 | memAccess->ThisAggr, false); 942 | } 943 | 944 | // Add this parameter 945 | args.push_back(val); 946 | ++it; 947 | } else { 948 | // Special case for member access with forced this 949 | MemberAccessExprAST* memAccess = (MemberAccessExprAST*)Callee; 950 | assert(memAccess->ThisSym->Parent == memAccess->ThisAggr); 951 | forcedReturn = (*it)->getRValue(Context); 952 | 953 | // Add this parameter 954 | args.push_back(forcedReturn); 955 | ++it; 956 | } 957 | } 958 | 959 | // Perform code generation for every function parameter 960 | for (ExprList::iterator end = Args.end(); it != end; ++it) { 961 | Value* v = (*it)->getRValue(Context); 962 | args.push_back(v); 963 | } 964 | 965 | if (forcedReturn) { 966 | // It's forced this. Create call and return calculated return value 967 | Context.TheBuilder->CreateCall(funcType, callee, args); 968 | return forcedReturn; 969 | } 970 | 971 | // Generate function's call 972 | return Context.TheBuilder->CreateCall(funcType, callee, args); 973 | } 974 | 975 | } // namespace simple --------------------------------------------------------------------------------