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 Feb 18, 2024
1 parent 39c0606 commit 2dc66ec
Show file tree
Hide file tree
Showing 21 changed files with 3,857 additions and 3 deletions.
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: '*'
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ 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/Type.cc
src/daedalus/TypeCheck.cc
src/daedalus/TypeStore.cc
src/DaedalusScript.cc
src/Date.cc
src/DaedalusVm.cc
Expand Down Expand Up @@ -74,6 +81,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
50 changes: 50 additions & 0 deletions assets/daedalus.abnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
ident = (ALPHA / "_") *(ALPHA / DIGIT / "_")
ident-qual = ident ["." ident]

literal-string = DQUOTE *(ALPHA / DIGIT / WSP / "!" / %x23-7E) DQUOTE
literal-int = 1*DIGIT
literal-float = 1*DIGIT ["." *DIGIT]
literal-array = "{" expr *("," expr) [","] "}"

expr-call-args = [expr *("," expr)]
expr-call = ident "(" expr-call-args ")"

expr-ref = ident-qual [ "[" expr "]" ]
expr-group = "(" expr ")"

expr-primary = literal-string / literal-int / literal-float / literal-array / expr-ref / expr-call / expr-group
expr-unary = (("!" / "+" / "-" / "~") expr-unary) / expr-primary
expr-factor = expr-unary [("*" / "/" / "%") expr]
expr-term = expr-factor [("+" / "-") expr]
expr-shift = expr-term [("<<" / ">>") expr]
expr-rel = expr-shift [("<" / "<=" / ">=" / ">") expr]
expr-equal = expr-rel [("==" / "!=") expr]
expr-bit = expr-equal [("&" / "|") expr]
expr-logic = expr-bit [("&&" / "||") expr]
expr-assign = expr-logic [( "=" / "+=" / "-=" / "*=" / "/=" ) expr]
expr = expr-assign

stmt-cond = "if" expr stmt-block *("else" "if" expr stmt-block) ["else" stmt-block]
stmt-return = "return" [expr]
stmt-decl = var-decl
stmt-expr = expr
stmt = stmt-cond / stmt-return / stmt-decl / stmt-expr

stmt-block = "{" *( stmt [";"] ) "}"

var-decl-single = "var" ident ident [ "[" expr "]" ]
var-decl-multi = "var" ident ident 1*("," ident)
var-decl = var-decl-single / var-decl-multi

const-decl = "const" ident ident [ "[" expr "]" ] "=" expr
class-decl = "class" ident "{" *(var-decl ";") "}"
inst-decl = "instance" ident *("," ident) "(" ident ")" [stmt-block]
proto-decl = "prototype" ident "(" ident ")" stmt-block

func-decl-args = "(" [ var-decl-single *("," var-decl-single) [","] ] ")"
func-decl = "func" ident ident func-decl-args stmt-block

extern-decl = "extern" "func" ident ident func-decl-args

script-decl-node = const-decl / var-decl / class-decl / proto-decl / inst-decl / func-decl / extern-decl
script-decl = *(script-decl-node ";")
322 changes: 322 additions & 0 deletions assets/extern.d

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ target_link_libraries(load_zen PRIVATE zenkit)
add_executable(run_interpreter run_interpreter.cc)
target_link_libraries(run_interpreter PRIVATE zenkit)

set_target_properties(load_vdf load_zen run_interpreter
PROPERTIES
add_executable(compile compile.cc)
target_link_libraries(compile PRIVATE zenkit)

set_target_properties(load_vdf load_zen run_interpreter compile
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/examples"
)
24 changes: 24 additions & 0 deletions examples/compile.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright © 2023 GothicKit Contributors.
// SPDX-License-Identifier: MIT
#include <zenkit/Logger.hh>
#include <zenkit/daedalus/Compiler.hh>

#include <iostream>

int main(int argc, char** argv) {
if (argc < 2) {
std::cerr << "Please provide a path to a script.";
return -1;
}

zenkit::Logger::set_default(zenkit::LogLevel::DEBUG);
zenkit::daedalus::Compiler compiler {};

compiler.add_src(argv[1]);
compiler.add("/mnt/projects/GothicKit/phoenix/assets/extern.d");

// compiler.add("/mnt/projects/GothicKit/phoenix/assets/test.d");
// compiler.add(argv[1]);
compiler.compile();
return 0;
}
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
211 changes: 211 additions & 0 deletions include/zenkit/daedalus/Module.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// Copyright © 2023 GothicKit Contributors.
// SPDX-License-Identifier: MIT
#pragma once
#include "zenkit/daedalus/SyntaxTree.hh"
#include "zenkit/daedalus/Type.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,
};

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 2dc66ec

Please sign in to comment.