Add decrement and negation unops

This commit is contained in:
Sofia 2026-04-28 00:38:04 +03:00
parent dd632b6bcc
commit 43df7efd6f
8 changed files with 104 additions and 12 deletions

View File

@ -99,6 +99,15 @@ namespace AST {
case types::Unary::AddPrefix: case types::Unary::AddPrefix:
out << "++" << this->m_expr->formatted(); out << "++" << this->m_expr->formatted();
break; 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: default:
break; break;
} }

View File

@ -109,8 +109,10 @@ namespace types {
new types::FundamentalType{ false, types::FundamentalTypeKind::Int } }; new types::FundamentalType{ false, types::FundamentalTypeKind::Int } };
auto char_ty = std::shared_ptr<types::Type>{ auto char_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ false, types::FundamentalTypeKind::Char } }; new types::FundamentalType{ false, types::FundamentalTypeKind::Char } };
auto bool_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } };
// Integer arithmetic binops // Integer Increment/Decrement unaries
for (auto& ty : { int_ty, char_ty }) { for (auto& ty : { int_ty, char_ty }) {
definitions.push_back(UnopDefinition{ definitions.push_back(UnopDefinition{
ty, types::Unary::AddPostfix, ty, ty, types::Unary::AddPostfix, ty,
@ -137,6 +139,48 @@ namespace types {
return result; return result;
} }
}); });
definitions.push_back(UnopDefinition{
ty, types::Unary::SubPostfix, ty,
[](codegen::Builder& builder, std::shared_ptr<Type> 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<llvm::Value*>(loaded);
}
});
definitions.push_back(UnopDefinition{
ty, types::Unary::SubPrefix, ty,
[](codegen::Builder& builder, std::shared_ptr<Type> 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<Type> 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; return definitions;

View File

@ -18,6 +18,9 @@ namespace types {
enum class Unary { enum class Unary {
AddPostfix, AddPostfix,
AddPrefix, AddPrefix,
SubPostfix,
SubPrefix,
Negation,
}; };
int operator_precedence(BinOp& op); int operator_precedence(BinOp& op);

View File

@ -454,6 +454,9 @@ namespace AST {
codegen::StackValue UnaryExpression::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) { 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 unary = types::find_unop(scope.unops, this->m_expr->get_codegen_type(scope), this->m_unary);
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 lvalue = scope.with_lvalue();
auto expr_ptr = this->m_expr->codegen(builder, lvalue, allocator); auto expr_ptr = this->m_expr->codegen(builder, lvalue, allocator);
return { return {
@ -461,6 +464,15 @@ namespace AST {
unary->res 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) { void ReturnStatement::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) {
if (!builder.block) if (!builder.block)

View File

@ -324,6 +324,23 @@ namespace parsing {
new AST::UnaryExpression(before_meta + inner.metadata(), std::move(expr), types::Unary::AddPrefix) 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<AST::Expression> {
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<AST::Expression> {
new AST::UnaryExpression(before_meta + inner.metadata(), std::move(expr), types::Unary::Negation)
};
}
auto plain_expr = parse_plain_expression(inner, scope); auto plain_expr = parse_plain_expression(inner, scope);
while (inner.peek().content == "(" || inner.peek().content == "[" || inner.peek().content == ".") { 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} 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<AST::Expression>{
new AST::UnaryExpression{before_meta + inner.metadata(), plain_expr.unwrap(), types::Unary::SubPostfix}
};
}
stream.m_position = inner.m_position; stream.m_position = inner.m_position;

View File

@ -547,7 +547,8 @@ namespace AST {
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
) { ) {
auto expr_res = this->m_expr->typecheck(state, scope, 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) { if (!expr_res.lvalue) {
state.errors.push_back(CompileError("Value must be a modifyable l-value", this->m_meta)); state.errors.push_back(CompileError("Value must be a modifyable l-value", this->m_meta));
} }
@ -564,7 +565,7 @@ namespace AST {
}; };
} }
else { 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 }; return { expr_res.type, false, false };
} }
} }

5
test.c
View File

@ -52,9 +52,8 @@ int main() {
printf("2d array: %d!\n", twod_array[0][0]); printf("2d array: %d!\n", twod_array[0][0]);
int counter = 0; int counter = 0;
printf("counter: %d\n", counter++); int a = !0;
printf("counter: %d\n", counter++); printf("a: %d\n", a);
printf("counter: %d\n", counter++);
return 0; return 0;
} }

0
tokei
View File