Skip to content

Commit

Permalink
feat(Daedalus): initial AST parser and initial type checker
Browse files Browse the repository at this point in the history
  • Loading branch information
lmichaelis committed Oct 6, 2023
1 parent 80f9654 commit b4de698
Show file tree
Hide file tree
Showing 15 changed files with 3,472 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Checks: '-*,bugprone-*,cppcoreguidelines-*,concurrency-*,clang-analyzer-*,hicpp-*,misc-*,modernize-*,performance-*,'
'portability-*,readability-*,-modernize-use-trailing-return-type,-cppcoreguidelines-pro-bounds-pointer-arithmetic,'
'-cppcoreguidelines-prefer-member-initializer'
'-cppcoreguidelines-prefer-member-initializer,-*-no-recursion'
WarningsAsErrors: '*'
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ list(APPEND _ZK_SOURCES
src/Archive.cc
src/Boxes.cc
src/CutsceneLibrary.cc
src/daedalus/Compiler.cc
src/daedalus/Module.cc
src/daedalus/SyntaxTree.cc
src/daedalus/Tokenizer.cc
src/daedalus/TypeCheck.cc
src/daedalus/TypeStore.cc
src/DaedalusScript.cc
src/Date.cc
src/DaedalusVm.cc
Expand Down Expand Up @@ -72,6 +78,7 @@ list(APPEND _ZK_TESTS
tests/TestArchive.cc
tests/TestCutsceneLibrary.cc
tests/TestDaedalusScript.cc
tests/TestDaedalusCompiler.cc
tests/TestFont.cc
tests/TestMaterial.cc
tests/TestModel.cc
Expand Down
68 changes: 68 additions & 0 deletions include/zenkit/daedalus/Compiler.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright © 2023 GothicKit Contributors.
// SPDX-License-Identifier: MIT
#pragma once
#include "zenkit/Error.hh"
#include "zenkit/Library.hh"
#include "zenkit/Stream.hh"

#include <filesystem>
#include <optional>
#include <string>
#include <unordered_set>

namespace zenkit::daedalus {
struct CompilationSource;

struct SourceLocation {
std::shared_ptr<CompilationSource> source;
std::size_t line {0}, column {0};

[[nodiscard]] std::string format() const;
};

class CompilerError : public Error {
public:
CompilerError(std::string type, SourceLocation loc, std::string message);

[[nodiscard]] std::string format() const;

public:
SourceLocation location;
std::string type;
};

class SyntaxError : public CompilerError {
public:
SyntaxError(SourceLocation loc, std::string message);
};

class TypeError : public CompilerError {
public:
TypeError(SourceLocation loc, std::string message);
};

struct CompilationSource {
explicit CompilationSource(std::filesystem::path const& path);
explicit CompilationSource(std::vector<std::byte> source);
explicit CompilationSource(std::unique_ptr<Read> source);

[[nodiscard]] std::string describe() const;

std::filesystem::path const path;
std::unique_ptr<Read> read;
};

bool operator==(CompilationSource const& a, CompilationSource const& b);

class Compiler {
public:
ZKAPI void add(std::filesystem::path const& source);
ZKAPI void add_raw(std::string_view source);
ZKAPI void add_src(std::filesystem::path const& source);

ZKAPI void compile();

private:
std::vector<std::shared_ptr<CompilationSource>> _m_sources;
};
} // namespace zenkit::daedalus
257 changes: 257 additions & 0 deletions include/zenkit/daedalus/Module.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
// Copyright © 2023 GothicKit Contributors.
// SPDX-License-Identifier: MIT
#pragma once
#include "zenkit/daedalus/SyntaxTree.hh"

#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>

namespace zenkit::daedalus {
enum class SymbolKind {
VAR,
CONST,
CLASS,
PROTOTYPE,
INSTANCE,
FUNC,
EXTERN,
};

enum class PrimitiveType {
VOID = 0,
INT,
INT_ARRAY,
FLOAT,
FLOAT_ARRAY,
STRING,
STRING_ARRAY,
FUNC,
FUNC_ARRAY,
};

class ClassSymbol;

class Type {
public:
explicit Type(PrimitiveType t);
explicit Type(ClassSymbol* t);

[[nodiscard]] bool is_convertible(Type other) const noexcept;

[[nodiscard]] bool is_primitive() const noexcept;
[[nodiscard]] bool is_void() const noexcept;
[[nodiscard]] bool is_array() const noexcept;
[[nodiscard]] Type to_array() const noexcept;
[[nodiscard]] Type to_elemental() const noexcept;

[[nodiscard]] PrimitiveType get_primitive_type() const;
[[nodiscard]] ClassSymbol* get_complex_type() const;

[[nodiscard]] std::string const& describe() const;

static Type VOID;
static Type INT;
static Type FLOAT;
static Type STRING;
static Type FUNC;

private:
friend bool operator==(Type a, Type b) noexcept;

std::variant<PrimitiveType, ClassSymbol*> _m_type;
};

bool operator==(Type a, Type b) noexcept;
bool operator!=(Type a, Type b) noexcept;

class Symbol {
public:
Symbol(SymbolKind type, std::string name);

Symbol(Symbol&&) = default;
virtual ~Symbol() noexcept = default;

[[nodiscard]] SymbolKind get_kind() const noexcept;
[[nodiscard]] std::string const& get_name() const noexcept;

protected:
SymbolKind _m_type;
std::string const _m_name;
};

class VarSymbol : public Symbol {
public:
VarSymbol(std::string name, Type type);
VarSymbol(std::string name, Type type, AstVariable ast);

[[nodiscard]] Type get_type() const;

void set_size(int size);
[[nodiscard]] int get_size() const;

[[nodiscard]] inline std::optional<AstVariable*> get_ast() noexcept {
if (_m_ast) return &*_m_ast;
return std::nullopt;
}

private:
Type _m_value_type;
int _m_size = 0;
std::optional<AstVariable> _m_ast;
};

class ConstSymbol : public Symbol {
public:
ConstSymbol(std::string name, Type type);
ConstSymbol(std::string name, Type type, AstConstant ast);

[[nodiscard]] Type get_type() const;

void set_size(int size);
[[nodiscard]] int get_size() const;

[[nodiscard]] inline std::optional<AstConstant*> get_ast() noexcept {
if (_m_ast) return &*_m_ast;
return std::nullopt;
}

private:
Type _m_value_type;
int _m_size = 0;
std::optional<AstConstant> _m_ast;
};

class Scope {
public:
std::vector<VarSymbol>& get_local_vars();

VarSymbol* add_local_var(std::string name, Type type, AstVariable ast);

private:
// TODO: For extra fine-grained control, properly scope these.
std::vector<VarSymbol> _m_local_vars;
};

class ClassSymbol : public Symbol {
public:
explicit ClassSymbol(std::string name);
ClassSymbol(std::string name, AstClass ast);

VarSymbol* get_member(std::string const& name);
VarSymbol* get_member(AstIdentifier const& name);

void add_member(std::string name, Type type);
void add_member(std::string name, Type type, AstVariable ast);

std::vector<VarSymbol>& get_members();

[[nodiscard]] inline std::optional<AstClass*> get_ast() noexcept {
if (_m_ast) return &*_m_ast;
return std::nullopt;
}

private:
std::vector<VarSymbol> _m_members;
std::optional<AstClass> _m_ast;
};

class PrototypeSymbol : public Symbol {
public:
PrototypeSymbol(std::string name, ClassSymbol* base);
PrototypeSymbol(std::string name, ClassSymbol* base, AstPrototype ast);

[[nodiscard]] ClassSymbol* get_base() const noexcept;

Scope& get_scope();

[[nodiscard]] inline std::optional<AstPrototype*> get_ast() noexcept {
if (_m_ast) return &*_m_ast;
return std::nullopt;
}

private:
ClassSymbol* _m_base;
std::optional<AstPrototype> _m_ast;
Scope _m_scope;
};

class InstanceSymbol : public Symbol {
public:
InstanceSymbol(std::string name, Symbol* base);
InstanceSymbol(std::string name, Symbol* base, AstInstance ast);

[[nodiscard]] Symbol* get_base() const noexcept;
[[nodiscard]] ClassSymbol* get_base_class() const noexcept;

Scope& get_scope();

[[nodiscard]] inline std::optional<AstInstance*> get_ast() noexcept {
if (_m_ast) return &*_m_ast;
return std::nullopt;
}

private:
Symbol* _m_base;
std::optional<AstInstance> _m_ast;
Scope _m_scope;
};

class FunctionSymbol : public Symbol {
public:
FunctionSymbol(std::string name, Type rtype);
FunctionSymbol(std::string name, Type rtype, AstFunction ast);

[[nodiscard]] Type get_return_type() const;

VarSymbol* get_argument(std::string const& name);
VarSymbol* get_argument(AstIdentifier const& name);

void add_argument(std::string name, Type type);
void add_argument(std::string name, Type type, AstVariable ast);

std::vector<VarSymbol>& get_arguments();

Scope& get_scope();

[[nodiscard]] inline std::optional<AstFunction*> get_ast() noexcept {
if (_m_ast) return &*_m_ast;
return std::nullopt;
}

private:
Type _m_return_type;
std::vector<VarSymbol> _m_args;
std::optional<AstFunction> _m_ast;
Scope _m_scope;
};

class ExternSymbol : public Symbol {
public:
ExternSymbol(std::string name, Type rtype);
ExternSymbol(std::string name, Type rtype, AstExternal ast);

[[nodiscard]] Type get_return_type() const;

VarSymbol* get_argument(std::string const& name);
VarSymbol* get_argument(AstIdentifier const& name);

void add_argument(std::string name, Type type);
void add_argument(std::string name, Type type, AstVariable ast);

std::vector<VarSymbol>& get_arguments();

[[nodiscard]] inline std::optional<AstExternal*> get_ast() noexcept {
if (_m_ast) return &*_m_ast;
return std::nullopt;
}

private:
Type _m_return_type;
std::vector<VarSymbol> _m_args;
std::optional<AstExternal> _m_ast;
};
} // namespace zenkit::daedalus
Loading

0 comments on commit b4de698

Please sign in to comment.