Skip to content
This repository has been archived by the owner on Jun 26, 2023. It is now read-only.

Commit

Permalink
feat: Add support for typing annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
xmnlab committed Jun 2, 2023
1 parent b5d0ca1 commit 1b980e5
Show file tree
Hide file tree
Showing 21 changed files with 379 additions and 124 deletions.
13 changes: 7 additions & 6 deletions .makim.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ env:
:print_legend=1\
:detect_leaks=1\
"
MESON_EXTRA: "-Db_coverage=true \
-Doptimization=0 \
MESON_EXTRA_DEBUG: "-Db_coverage=true \
--optimization=0 \
--debug \
-Db_sanitize=address \
"
groups:
Expand Down Expand Up @@ -104,7 +105,7 @@ groups:
- target: build.release
args:
build-type: "debug"
meson-extra: {{ env.MESON_EXTRA }}
meson-extra: {{ env.MESON_EXTRA_DEBUG }}
clean: {{ args.clean }}
asan-options: {{ env.SAN_OPTIONS_DEFAULT }}
lsan-options: {{ env.SAN_OPTIONS_DEFAULT }}
Expand All @@ -120,7 +121,7 @@ groups:
- target: build.release
args:
build-type: "debug"
meson-extra: {{ env.MESON_EXTRA }} -Ddev=enabled
meson-extra: {{ env.MESON_EXTRA_DEBUG }} -Ddev=enabled
clean: {{ args.clean }}
asan-options: {{ env.SAN_OPTIONS_DEFAULT }}
lsan-options: {{ env.SAN_OPTIONS_DEFAULT }}
Expand Down Expand Up @@ -231,7 +232,7 @@ groups:
if [[ "{{ args.debug }}" == "True" ]]; then
GDB="gdb --args"
DEBUG_FLAGS="-g"
DEBUG_FLAGS="-Og"
fi
TEST_DIR_PATH="./tests"
Expand Down Expand Up @@ -261,7 +262,7 @@ groups:
print_header "${test_name}"
OBJECT_FILE="${TMP_DIR}/${test_name}.o"
${ARX} --output "${OBJECT_FILE}" --input "examples/${test_name}.arx"
${ARX} --output "${OBJECT_FILE}" --input "examples/${test_name}.arx --build-lib"
set -x
clang++ \
Expand Down
4 changes: 2 additions & 2 deletions examples/average.arx
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
function average(x y):
(x + y) * 0.5;
fn average(x: float, y: float) -> float:
return (x + y) * 0.5;
4 changes: 2 additions & 2 deletions examples/constant.arx
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
function get_constant(x):
x;
fn get_constant(x: float) -> float:
return x;
8 changes: 4 additions & 4 deletions examples/fibonacci.arx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function fib(x):
if x < 3:
1
fn fib(x: float) -> float:
if x <= 1:
return x;
else:
fib(x-1)+fib(x-2)
return fib(x-1)+fib(x-2);
6 changes: 3 additions & 3 deletions examples/print-star.arx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extern putchard(char);
extern putchard(char) -> void;

function print_star(n):
fn print_star(n: float) -> void:
for i = 1, i < n, 1.0 in
putchard(42); # ascii 42 = '*'
return putchard(42); # ascii 42 = '*'
4 changes: 2 additions & 2 deletions examples/sum.arx
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
function sum(a b):
a + b;
fn sum(a: float, b: float) -> float:
return a + b;
3 changes: 2 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ project('arx', 'cpp', 'c',
license : 'Apache-2.0',
version : '1.6.0', # semantic-release
default_options : [
'warning_level=everything',
#'warning_level=everything',
'warning_level=1',
'cpp_std=c++20',
]
)
Expand Down
21 changes: 21 additions & 0 deletions src/codegen/arx-llvm.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <string>

#include <llvm/IR/DIBuilder.h> // for DIBuilder
#include <llvm/IR/IRBuilder.h> // for IRBuilder
Expand All @@ -22,6 +23,26 @@ llvm::Type* ArxLLVM::FLOAT_TYPE;
llvm::Type* ArxLLVM::DOUBLE_TYPE;
llvm::Type* ArxLLVM::INT8_TYPE;
llvm::Type* ArxLLVM::INT32_TYPE;
llvm::Type* ArxLLVM::VOID_TYPE;

auto ArxLLVM::get_data_type(std::string type_name) -> llvm::Type* {
if (type_name == "float") {
return ArxLLVM::FLOAT_TYPE;
} else if (type_name == "double") {
return ArxLLVM::DOUBLE_TYPE;
} else if (type_name == "int8") {
return ArxLLVM::INT8_TYPE;
} else if (type_name == "int32") {
return ArxLLVM::INT32_TYPE;
} else if (type_name == "char") {
return ArxLLVM::INT8_TYPE;
} else if (type_name == "void") {
return ArxLLVM::VOID_TYPE;
}

llvm::errs() << "[EE] type_name not valid.\n";
return nullptr;
}

/* Debug Information Data types */
llvm::DIType* ArxLLVM::DI_FLOAT_TYPE;
Expand Down
44 changes: 33 additions & 11 deletions src/codegen/ast-to-object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ auto ASTToObjectVisitor::getFunction(std::string name) -> void {
*/
auto ASTToObjectVisitor::CreateEntryBlockAlloca(
llvm::Function* fn, llvm::StringRef var_name) -> llvm::AllocaInst* {
llvm::IRBuilder<> TmpB(&fn->getEntryBlock(), fn->getEntryBlock().begin());
return TmpB.CreateAlloca(ArxLLVM::FLOAT_TYPE, nullptr, var_name);
llvm::IRBuilder<> tmp_builder(
&fn->getEntryBlock(), fn->getEntryBlock().begin());
return tmp_builder.CreateAlloca(ArxLLVM::FLOAT_TYPE, nullptr, var_name);
}

/**
Expand Down Expand Up @@ -165,7 +166,7 @@ auto ASTToObjectVisitor::visit(UnaryExprAST& expr) -> void {
*
*/
auto ASTToObjectVisitor::visit(BinaryExprAST& expr) -> void {
// Special case '=' because we don't want to emit the lhs as an
// Special case '=' because we don't want to emit the lhs as an
// expression.*/
if (expr.op == '=') {
// Assignment requires the lhs to be an identifier.
Expand All @@ -188,13 +189,13 @@ auto ASTToObjectVisitor::visit(BinaryExprAST& expr) -> void {
};

// Look up the name.//
llvm::Value* Variable = ArxLLVM::named_values[var_lhs->get_name()];
if (!Variable) {
llvm::Value* variable = ArxLLVM::named_values[LHSE->getName()];
if (!variable) {
this->result_val = LogErrorV("Unknown variable name");
return;
}

ArxLLVM::ir_builder->CreateStore(val, Variable);
ArxLLVM::ir_builder->CreateStore(val, variable);
this->result_val = val;
}

Expand Down Expand Up @@ -520,11 +521,32 @@ auto ASTToObjectVisitor::visit(VarExprAST& expr) -> void {
*
*/
auto ASTToObjectVisitor::visit(PrototypeAST& expr) -> void {
std::vector<llvm::Type*> args_type(expr.args.size(), ArxLLVM::FLOAT_TYPE);
llvm::Type* return_type = ArxLLVM::get_data_type("float");
// Make the function type: double(double,double) etc.
std::vector<llvm::Type*> args;
llvm::Type* arg_type;

for (auto& arg : expr.args) {
arg_type = ArxLLVM::get_data_type(arg->type_name);
if (arg_type != nullptr) {
args.emplace_back(arg_type);
} else {
llvm::errs() << "ARX::GEN-OBJECT[ERROR]: PrototypeAST: "
<< "Argument data type " << arg->type_name
<< " not implemented yet.";
}
}

llvm::Type* return_type = ArxLLVM::get_data_type(expr.type_name);

if (return_type == nullptr) {
llvm::errs() << "ARX::GEN-OBJECT[ERROR]: PrototypeAST: "
<< "Argument data type " << expr.type_name
<< " not implemented yet.";
}

llvm::FunctionType* fn_type =
llvm::FunctionType::get(return_type, args_type, false /* isVarArg */);
llvm::FunctionType* fn_type = llvm::FunctionType::get(
return_type, args, false /* isVarArg */
);

llvm::Function* fn = llvm::Function::Create(
fn_type,
Expand Down Expand Up @@ -794,7 +816,7 @@ auto compile_object(TreeAST& tree_ast) -> int {
std::cout << "ARX[INFO]: " << compiler_cmd << std::endl;
int compile_result = system(compiler_cmd.c_str());

// ArxFile::delete_file(main_cpp_path);
ArxFile::delete_file(main_cpp_path);

if (compile_result != 0) {
llvm::errs() << "failed to compile and link object file";
Expand Down
46 changes: 26 additions & 20 deletions src/codegen/ast-to-stdout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@

int INDENT_SIZE = 2;

class ASTToOutputVisitor
: public std::enable_shared_from_this<ASTToOutputVisitor>,
public Visitor {
class ASTToOutputVisitor : public Visitor {
public:
int indent = 0;
std::string annotation = "";
Expand Down Expand Up @@ -53,12 +51,21 @@ void ASTToOutputVisitor::visit(FloatExprAST& expr) {

void ASTToOutputVisitor::visit(VariableExprAST& expr) {
std::cout << this->indentation() << this->get_annotation()
<< "(VariableExprAST " << expr.name << ")";
<< "(VariableExprAST " << expr.name << ":" << expr.type_name
<< ")";
}

void ASTToOutputVisitor::visit(UnaryExprAST& expr) {
std::cout << "(UnaryExprAST"
<< ")" << std::endl;
std::cout << this->indentation() << "(UnaryExprAST op_code:" << expr.op_code
<< " operand:";

int cur_indent = this->indent;
this->indent = 0;

expr.operand->accept(*this);
std::cout << ")";

this->indent = cur_indent;
}

void ASTToOutputVisitor::visit(BinaryExprAST& expr) {
Expand Down Expand Up @@ -197,29 +204,28 @@ void ASTToOutputVisitor::visit(VarExprAST& expr) {

void ASTToOutputVisitor::visit(PrototypeAST& expr) {
// TODO: implement it
std::cout << "(PrototypeAST " << expr.name << ")" << std::endl;
}

void ASTToOutputVisitor::visit(FunctionAST& expr) {
std::cout << this->indentation() << '(' << std::endl;
this->indent += INDENT_SIZE;

// create the function and open the args section
std::cout << this->indentation() << "Function " << expr.proto->name
std::cout << "(PrototypeAST " << expr.name << ") -> " << expr.type_name
<< " <ARGS> (" << std::endl;
this->indent += INDENT_SIZE;

// std::cout << expr.proto->args.front();

for (const auto& node : expr.proto->args) {
for (const auto& node : expr.args) {
node->accept(*this);
std::cout << ", " << std::endl;
}

// close args section and open body section
this->indent -= INDENT_SIZE;
std::cout << this->indentation() << "), " << std::endl
<< this->indentation() << "<BODY> (" << std::endl;
std::cout << this->indentation() << "), " << std::endl;
}

void ASTToOutputVisitor::visit(FunctionAST& expr) {
std::cout << this->indentation() << '(' << std::endl;
this->indent += INDENT_SIZE;

// create the function and open the args section
std::cout << this->indentation() << "Function ";
this->visit(*expr.proto);
std::cout << this->indentation() << "<BODY> (" << std::endl;

this->indent += INDENT_SIZE;
// TODO: body should be a vector of unique_ptr<Expr>
Expand Down
17 changes: 14 additions & 3 deletions src/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,23 @@ namespace llvm {
} // namespace llvm

/**
* @brief LogError* - These are little helper functions for error handling.
* @brief LogError* - A little helper function for error handling.
*
*/
template <typename T>
std::unique_ptr<T> LogError(const char* Str) {
fprintf(stderr, "Error: %s\n", Str);
std::unique_ptr<T> LogError(const char* msg) {
fprintf(stderr, "Error: %s\n", msg);
return nullptr;
}

/**
* @brief LogError* - A little helper function for error handling with line
* and col information.
*
*/
template <typename T>
std::unique_ptr<T> LogParserError(const char* msg, int line, int col) {
fprintf(stderr, "ParserError[%i:%i]: %s\n", line, col, msg);
return nullptr;
}

Expand Down
57 changes: 56 additions & 1 deletion src/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,55 @@ auto Lexer::get_tok_name(int tok) -> std::string {
return "var";
case tok_const:
return "const";
case tok_arrow_right:
return "->";
}
return std::string(1, static_cast<char>(Tok));
}

/**
* @brief Get the Token name to be used in a message.
* @param Tok The token
* @return Token name
*
*/
auto Lexer::get_tok_name_display(int Tok) -> std::string {
switch (Tok) {
case tok_eof:
return "<eof>";
case tok_function:
return "<function>";
case tok_return:
return "<return>";
case tok_extern:
return "<extern>";
case tok_identifier:
return "<identifier>";
case tok_float_literal:
return "<float>";
case tok_if:
return "<if>";
case tok_then:
return "<then>";
case tok_else:
return "<else>";
case tok_for:
return "<for>";
case tok_in:
return "<in>";
case tok_binary:
return "<binary>";
case tok_unary:
return "<unary>";
case tok_var:
return "<var>";
case tok_const:
return "<const>";
case tok_arrow_right:
return "->";
case tok_expression:
// just used for error message
return "<expression>";
}
return std::string(1, static_cast<char>(tok));
}
Expand Down Expand Up @@ -114,7 +163,7 @@ auto Lexer::gettok() -> int {
Lexer::identifier_str += last_char;
}

if (Lexer::identifier_str == "function") {
if (Lexer::identifier_str == "fn") {
return tok_function;
}
if (Lexer::identifier_str == "return") {
Expand Down Expand Up @@ -178,6 +227,12 @@ auto Lexer::gettok() -> int {
// Otherwise, just return the character as its ascii value.
int this_char = last_char;
last_char = static_cast<char>(Lexer::advance());

if (this_char == (int) '-' && last_char == (int) '>') {
last_char = static_cast<char>(Lexer::advance());
return tok_arrow_right;
}

return this_char;
}

Expand Down
Loading

0 comments on commit 1b980e5

Please sign in to comment.