Skip to content

Commit

Permalink
feat: add control flow analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
jsilll committed Sep 24, 2024
1 parent 43c7a83 commit 4830cf6
Show file tree
Hide file tree
Showing 35 changed files with 516 additions and 212 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[//]: # (TODO: Update README)

# Lang Compiler (Name TBD)

This project is an LLVM-based compiler for a custom programming language called "Lang".
Expand Down
7 changes: 2 additions & 5 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/bin/bash

# Default values for variables
set -e

LLVM_DIR="/usr/lib/llvm-14"
BUILD_DIR="build"
BUILD_TYPE="Debug"
Expand All @@ -9,7 +10,6 @@ CXX_COMPILER="clang++"
CCACHE="ccache"
GENERATOR="Ninja"

# Function to display usage information
usage() {
echo "Usage: $0 <command> [options]"
echo "Commands:"
Expand All @@ -28,7 +28,6 @@ usage() {
exit 1
}

# Parse command-line options
while [[ $# -gt 0 ]]; do
case $1 in
--build-dir)
Expand Down Expand Up @@ -65,12 +64,10 @@ while [[ $# -gt 0 ]]; do
esac
done

# Check if a command is provided
if [ $# -eq 0 ]; then
usage
fi

# Execute the appropriate command
case "$1" in
configure)
mkdir -p "$BUILD_DIR"
Expand Down
31 changes: 10 additions & 21 deletions include/ADT/List.h → include/ADT/NonOwningList.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
#ifndef LANG_LIST_H
#define LANG_LIST_H
#ifndef LANG_NON_OWNING_LIST_H
#define LANG_NON_OWNING_LIST_H

#include <cstddef>
#include <iterator>

/// @brief A singly linked list.
/// @tparam T The type of the elements in the list.
///
/// @note This is a raw implementation of a singly linked list. It is meant to
/// replace allocating alternatives like std::vector and std::list. This way,
/// the caller can decide how to allocate the nodes, and the list will not
/// delete them on destruction. For now this is used in the AST representation
/// since the whole AST is allocated in one contiguous block of memory with no
/// RAII semantics. This discards having nodes that are not trivially
/// destructible, as would happen if std::vector or std::list were used in nodes
/// with a variable number of children (e.g. BlockStmtAST).
template <typename T> class List {
template <typename T> class NonOwningList {
public:
struct Node {
T data;
Expand Down Expand Up @@ -98,14 +87,14 @@ template <typename T> class List {
const Node *cur;
};

List() noexcept : head(nullptr), tail(nullptr), size_(0) {}
~List() = default;
NonOwningList() noexcept : head(nullptr), tail(nullptr), size_(0) {}
~NonOwningList() = default;

List(List &&) = delete;
List &operator=(List &&) = delete;
NonOwningList(NonOwningList &&) = delete;
NonOwningList &operator=(NonOwningList &&) = delete;

List(const List &) = default;
List &operator=(const List &) = default;
NonOwningList(const NonOwningList &) = default;
NonOwningList &operator=(const NonOwningList &) = default;

[[nodiscard]] bool empty() const noexcept { return size_ == 0; }
[[nodiscard]] std::size_t size() const noexcept { return size_; }
Expand Down Expand Up @@ -190,4 +179,4 @@ template <typename T> class List {
std::size_t size_;
};

#endif // LANG_LIST_H
#endif // LANG_NON_OWNING_LIST_H
19 changes: 10 additions & 9 deletions include/AST/AST.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#ifndef LANG_AST_H
#define LANG_AST_H

#include "ADT/List.h"
#include "ADT/NonOwningList.h"

#include "Sema/Type.h"
#include "Typing/Type.h"

#include <string_view>
#include <variant>
Expand Down Expand Up @@ -94,8 +94,8 @@ struct DeclAST {

struct ModuleAST {
std::string_view ident;
List<DeclAST *> decls;
ModuleAST(std::string_view ident, List<DeclAST *> decls)
NonOwningList<DeclAST *> decls;
ModuleAST(std::string_view ident, NonOwningList<DeclAST *> decls)
: ident(ident), decls(decls) {}
};

Expand Down Expand Up @@ -182,8 +182,8 @@ struct AssignStmtAST : public StmtAST {
};

struct BlockStmtAST : public StmtAST {
List<StmtAST *> stmts;
BlockStmtAST(std::string_view span, List<StmtAST *> stmts)
NonOwningList<StmtAST *> stmts;
BlockStmtAST(std::string_view span, NonOwningList<StmtAST *> stmts)
: StmtAST(StmtASTKind::Block, span), stmts(stmts) {}
};

Expand All @@ -207,11 +207,12 @@ struct WhileStmtAST : public StmtAST {
/// === Declarations ===

struct FunctionDeclAST : public DeclAST {
List<LocalStmtAST *> params;
NonOwningList<LocalStmtAST *> params;
Type *retType;
BlockStmtAST *body;
FunctionDeclAST(std::string_view ident, List<LocalStmtAST *> params,
Type *retType, BlockStmtAST *body)
FunctionDeclAST(std::string_view ident,
NonOwningList<LocalStmtAST *> params, Type *retType,
BlockStmtAST *body)
: DeclAST(DeclASTKind::Function, ident), params(params),
retType(retType), body(body) {}
};
Expand Down
75 changes: 75 additions & 0 deletions include/Analysis/CFA.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#ifndef LANG_CONTROL_FLOW_ANALYZER
#define LANG_CONTROL_FLOW_ANALYZER

#include "Support/Reporting.h"

#include "AST/ASTVisitor.h"

#include <stack>

namespace lang {

enum class CFAErrorKind {
EarlyReturnStmt,
InvalidBreakStmt,
};

struct CFAError {
CFAErrorKind kind;
std::string_view span;
CFAError(CFAErrorKind kind, std::string_view span)
: kind(kind), span(span) {}
TextError toTextError() const;
JSONError toJSONError() const;
};

struct CFAResult {
std::vector<CFAError> errors;
};

class CFA : public MutableASTVisitor<CFA> {
friend class ASTVisitor<CFA, false>;

public:
CFAResult analyzeModuleAST(ModuleAST &module);

private:
std::stack<StmtAST *> breakableStack;
std::vector<CFAError> errors;

void visit(FunctionDeclAST &node);

void visit(ExprStmtAST &node) {}

void visit(BreakStmtAST &node);

void visit(ReturnStmtAST &node) {}

void visit(LocalStmtAST &node) {}

void visit(AssignStmtAST &node) {}

void visit(BlockStmtAST &node);

void visit(IfStmtAST &node);

void visit(WhileStmtAST &node);

void visit(IdentifierExprAST &node) {}

void visit(NumberExprAST &node) {}

void visit(UnaryExprAST &node) {}

void visit(BinaryExprAST &node) {}

void visit(CallExprAST &node) {}

void visit(IndexExprAST &node) {}

void visit(GroupedExprAST &node) {}
};

} // namespace lang

#endif // LANG_CONTROL_FLOW_ANALYZER
11 changes: 3 additions & 8 deletions include/Sema/Resolver.h → include/Analysis/Resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,14 @@

#include "Support/Reporting.h"

#include "AST/AST.h"
#include "AST/ASTVisitor.h"

#include <stack>
#include <unordered_map>
#include <vector>

namespace lang {

enum class ResolveErrorKind {
InvalidBreakStmt,
UnresolvedIdentifier,
UnknownIdentifier,
};

struct ResolveError {
Expand All @@ -40,7 +36,6 @@ class Resolver : public MutableASTVisitor<Resolver> {

private:
bool deepResolution;
std::stack<StmtAST *> breakableStack;
std::unordered_map<std::string_view, FunctionDeclAST *> functionsMap;
std::vector<std::unordered_map<std::string_view, LocalStmtAST *>> localsMap;
std::vector<ResolveError> errors;
Expand All @@ -51,7 +46,7 @@ class Resolver : public MutableASTVisitor<Resolver> {

void visit(ExprStmtAST &node);

void visit(BreakStmtAST &node);
void visit(BreakStmtAST &node) {}

void visit(ReturnStmtAST &node);

Expand All @@ -67,7 +62,7 @@ class Resolver : public MutableASTVisitor<Resolver> {

void visit(IdentifierExprAST &node);

void visit(NumberExprAST &node);
void visit(NumberExprAST &node) {}

void visit(UnaryExprAST &node);

Expand Down
30 changes: 16 additions & 14 deletions include/Sema/Sema.h → include/Analysis/TypeChecker.h
Original file line number Diff line number Diff line change
@@ -1,50 +1,52 @@
#ifndef LANG_SEMA_H
#define LANG_SEMA_H
#ifndef LANG_TYPE_CHECKER_H
#define LANG_TYPE_CHECKER_H

#include "Support/Reporting.h"

#include "AST/AST.h"
#include "AST/ASTVisitor.h"

#include "Typing/TypeContext.h"

#include <vector>

namespace lang {

enum class SemaErrorKind {
enum class TypeCheckerErrorKind {
InvalidReturn,
InvalidAssignment,
InvalidBinaryOperation,
};

struct SemaError {
SemaErrorKind kind;
struct TypeCheckerError {
TypeCheckerErrorKind kind;
std::string_view span;
TextError toTextError() const;
JSONError toJSONError() const;
};

struct SemaResult {
std::vector<SemaError> errors;
struct TypeCheckerResult {
std::vector<TypeCheckerError> errors;
};

class Sema : public MutableASTVisitor<Sema> {
friend class ASTVisitor<Sema, false>;
class TypeChecker : public MutableASTVisitor<TypeChecker> {
friend class ASTVisitor<TypeChecker, false>;

public:
Sema(TypeContext &typeCtx) : typeCtx(typeCtx), currentFunction(nullptr) {}
TypeChecker(TypeContext &typeCtx) : typeCtx(typeCtx), currentFunction(nullptr) {}

SemaResult analyzeModuleAST(ModuleAST &module);
TypeCheckerResult analyzeModuleAST(ModuleAST &module);

private:
TypeContext &typeCtx;
FunctionDeclAST *currentFunction;
std::vector<SemaError> errors;
std::vector<TypeCheckerError> errors;

void visit(FunctionDeclAST &node);

void visit(ExprStmtAST &node);

void visit(BreakStmtAST &node);
void visit(BreakStmtAST &node) {}

void visit(ReturnStmtAST &node);

Expand Down Expand Up @@ -75,4 +77,4 @@ class Sema : public MutableASTVisitor<Sema> {

} // namespace lang

#endif // LANG_SEMA_H
#endif // LANG_TYPE_CHECKER
4 changes: 2 additions & 2 deletions include/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#include "AST/AST.h"

#include "Sema/Type.h"
#include "Typing/TypeContext.h"

#include <unordered_set>

Expand All @@ -18,7 +18,7 @@ namespace lang {
enum class ParseErrorKind {
UnexpectedEOF,
UnexpectedToken,
ExpectedTypeAnnotation,
ExpectedType,
ExpectedPrimaryExpression,
};

Expand Down
6 changes: 3 additions & 3 deletions include/Support/Debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
#ifndef NDEBUG
#define DEBUG(...) \
do { \
fprintf(stderr, "[%s:%d] ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
fprintf(stdout, "[%s:%d] ", __FILE__, __LINE__); \
fprintf(stdout, __VA_ARGS__); \
fprintf(stdout, "\n"); \
} while (0)
#else
#define DEBUG(...)
Expand Down
Loading

0 comments on commit 4830cf6

Please sign in to comment.