diff --git a/src/ast.cpp b/src/ast.cpp index 955f0ce..88bde97 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -99,6 +99,15 @@ namespace AST { case types::Unary::AddPrefix: out << "++" << this->m_expr->formatted(); break; + case types::Unary::SubPostfix: + out << this->m_expr->formatted() << "--"; + break; + case types::Unary::SubPrefix: + out << "--" << this->m_expr->formatted(); + break; + case types::Unary::Negation: + out << "!" << this->m_expr->formatted(); + break; default: break; } diff --git a/src/binops.cpp b/src/binops.cpp index c91779d..7e5fa64 100644 --- a/src/binops.cpp +++ b/src/binops.cpp @@ -109,8 +109,10 @@ namespace types { new types::FundamentalType{ false, types::FundamentalTypeKind::Int } }; auto char_ty = std::shared_ptr{ new types::FundamentalType{ false, types::FundamentalTypeKind::Char } }; + auto bool_ty = std::shared_ptr{ + new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; - // Integer arithmetic binops + // Integer Increment/Decrement unaries for (auto& ty : { int_ty, char_ty }) { definitions.push_back(UnopDefinition{ ty, types::Unary::AddPostfix, ty, @@ -137,6 +139,48 @@ namespace types { return result; } }); + + definitions.push_back(UnopDefinition{ + ty, types::Unary::SubPostfix, ty, + [](codegen::Builder& builder, std::shared_ptr ty, llvm::Value* ptr) { + codegen::TypeMap structs {}; + auto llvm_ty = ty->codegen(builder, structs); + auto loaded = builder.builder->CreateLoad(llvm_ty, ptr); + auto const_1 = llvm::ConstantInt::get(llvm_ty, 1); + auto result = builder.builder->CreateSub(loaded, const_1, "sub"); + builder.builder->CreateStore(result, ptr); + return reinterpret_cast(loaded); + } + }); + + definitions.push_back(UnopDefinition{ + ty, types::Unary::SubPrefix, ty, + [](codegen::Builder& builder, std::shared_ptr ty, llvm::Value* ptr) { + codegen::TypeMap structs {}; + auto llvm_ty = ty->codegen(builder, structs); + auto loaded = builder.builder->CreateLoad(llvm_ty, ptr); + auto const_1 = llvm::ConstantInt::get(llvm_ty, 1); + auto result = builder.builder->CreateSub(loaded, const_1, "sub"); + builder.builder->CreateStore(result, ptr); + return result; + } + }); + } + + // Negation + for (auto& ty : { int_ty, char_ty, bool_ty }) { + definitions.push_back(UnopDefinition{ + ty, types::Unary::Negation, ty, + [](codegen::Builder& builder, std::shared_ptr ty, llvm::Value* value) { + codegen::TypeMap structs {}; + auto llvm_ty = ty->codegen(builder, structs); + auto const_1 = llvm::ConstantInt::get(llvm_ty, 1); + auto const_0 = llvm::ConstantInt::get(llvm_ty, 0); + + auto cmp = builder.builder->CreateICmp(llvm::CmpInst::Predicate::ICMP_EQ, value, const_0, "not_cmp"); + return builder.builder->CreateSelect(cmp, const_1, const_0, "not_select"); + } + }); } return definitions; diff --git a/src/binops.h b/src/binops.h index c920f06..0fb37f2 100644 --- a/src/binops.h +++ b/src/binops.h @@ -18,6 +18,9 @@ namespace types { enum class Unary { AddPostfix, AddPrefix, + SubPostfix, + SubPrefix, + Negation, }; int operator_precedence(BinOp& op); diff --git a/src/codegen.cpp b/src/codegen.cpp index f90a63b..84a739d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -454,12 +454,24 @@ namespace AST { codegen::StackValue UnaryExpression::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) { auto unary = types::find_unop(scope.unops, this->m_expr->get_codegen_type(scope), this->m_unary); - auto lvalue = scope.with_lvalue(); - auto expr_ptr = this->m_expr->codegen(builder, lvalue, allocator); - return { - unary->codegen(builder, this->m_expr->get_codegen_type(scope), expr_ptr.value), - unary->res - }; + + if (this->m_unary == types::Unary::AddPostfix || this->m_unary == types::Unary::AddPrefix + || this->m_unary == types::Unary::SubPostfix || this->m_unary == types::Unary::SubPrefix) { + auto lvalue = scope.with_lvalue(); + auto expr_ptr = this->m_expr->codegen(builder, lvalue, allocator); + return { + unary->codegen(builder, this->m_expr->get_codegen_type(scope), expr_ptr.value), + unary->res + }; + } + else { + auto expr_ptr = this->m_expr->codegen(builder, scope, allocator); + return { + unary->codegen(builder, this->m_expr->get_codegen_type(scope), expr_ptr.value), + unary->res + }; + } + } void ReturnStatement::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) { diff --git a/src/parsing.cpp b/src/parsing.cpp index 3b0472e..babd3d4 100644 --- a/src/parsing.cpp +++ b/src/parsing.cpp @@ -324,6 +324,23 @@ namespace parsing { new AST::UnaryExpression(before_meta + inner.metadata(), std::move(expr), types::Unary::AddPrefix) }; } + else if (inner.peek().content == "-" && inner.peek(1).content == "-") { + inner.next(); + inner.next(); + auto expr = parse_primary_expression(inner, scope).unwrap(); + stream.m_position = inner.m_position; + return std::unique_ptr { + new AST::UnaryExpression(before_meta + inner.metadata(), std::move(expr), types::Unary::SubPrefix) + }; + } + else if (inner.peek().content == "!") { + inner.next(); + auto expr = parse_primary_expression(inner, scope).unwrap(); + stream.m_position = inner.m_position; + return std::unique_ptr { + new AST::UnaryExpression(before_meta + inner.metadata(), std::move(expr), types::Unary::Negation) + }; + } auto plain_expr = parse_plain_expression(inner, scope); while (inner.peek().content == "(" || inner.peek().content == "[" || inner.peek().content == ".") { @@ -366,6 +383,13 @@ namespace parsing { new AST::UnaryExpression{before_meta + inner.metadata(), plain_expr.unwrap(), types::Unary::AddPostfix} }; } + else if (inner.peek().content == "-" && inner.peek(1).content == "-") { + inner.next(); + inner.next(); + plain_expr = std::unique_ptr{ + new AST::UnaryExpression{before_meta + inner.metadata(), plain_expr.unwrap(), types::Unary::SubPostfix} + }; + } stream.m_position = inner.m_position; diff --git a/src/typechecker.cpp b/src/typechecker.cpp index 5499c15..cab217e 100644 --- a/src/typechecker.cpp +++ b/src/typechecker.cpp @@ -547,7 +547,8 @@ namespace AST { std::optional> expected_ty ) { auto expr_res = this->m_expr->typecheck(state, scope, expected_ty); - if (this->m_unary == types::Unary::AddPostfix || this->m_unary == types::Unary::AddPrefix) { + if (this->m_unary == types::Unary::AddPostfix || this->m_unary == types::Unary::AddPrefix + || this->m_unary == types::Unary::SubPostfix || this->m_unary == types::Unary::SubPrefix) { if (!expr_res.lvalue) { state.errors.push_back(CompileError("Value must be a modifyable l-value", this->m_meta)); } @@ -564,7 +565,7 @@ namespace AST { }; } else { - state.errors.push_back(CompileError("No suitable unary operator found", this->m_meta)); + state.errors.push_back(CompileError("No suitable unary operator found for " + this->formatted(), this->m_meta)); return { expr_res.type, false, false }; } } diff --git a/test.c b/test.c index 5e5eced..6da34df 100644 --- a/test.c +++ b/test.c @@ -52,9 +52,8 @@ int main() { printf("2d array: %d!\n", twod_array[0][0]); int counter = 0; - printf("counter: %d\n", counter++); - printf("counter: %d\n", counter++); - printf("counter: %d\n", counter++); + int a = !0; + printf("a: %d\n", a); return 0; } \ No newline at end of file diff --git a/tokei b/tokei deleted file mode 100644 index e69de29..0000000