From d1c85ae6e8a52be8c5833ba37c938e5d27d7271e Mon Sep 17 00:00:00 2001 From: Jack Parsons Date: Tue, 2 Jul 2024 13:47:27 -0600 Subject: [PATCH] 64 Bit Integers (#44) * add i64 * add extra type check tests --- grammar/Fusion.g4 | 4 ++- include/ast/ast.h | 6 ++-- include/backend/types/integer.h | 1 + include/shared/context.h | 3 +- include/shared/type/integer.h | 8 +++++ src/ast/ast.cpp | 15 +++++----- src/ast/builder.cpp | 20 +++++++++---- src/ast/passes/type_check.cpp | 33 ++++++++++++--------- src/backend/builtin/print.cpp | 2 +- src/backend/expressions/arithmetic.cpp | 8 ++--- src/backend/types/boolean.cpp | 2 +- src/backend/types/integer.cpp | 7 +++++ src/backend/visitor.cpp | 6 +++- src/shared/context.cpp | 11 ++++--- src/shared/type/integer.cpp | 14 +++++++++ tests/input/declaration/basic.in | 3 ++ tests/input/errors/syntax/int_overflow.in | 4 +++ tests/input/errors/type/int_sizes.in | 4 +++ tests/output/declaration/basic.out | 1 + tests/output/errors/syntax/int_overflow.out | 1 + tests/output/errors/type/int_sizes.out | 1 + 21 files changed, 109 insertions(+), 45 deletions(-) create mode 100644 tests/input/errors/syntax/int_overflow.in create mode 100644 tests/input/errors/type/int_sizes.in create mode 100644 tests/output/errors/syntax/int_overflow.out create mode 100644 tests/output/errors/type/int_sizes.out diff --git a/grammar/Fusion.g4 b/grammar/Fusion.g4 index 2ceb6f5..387fcfc 100644 --- a/grammar/Fusion.g4 +++ b/grammar/Fusion.g4 @@ -45,7 +45,8 @@ expr qualifier: CONST | LET; type - : I32 + : I32 + | I64 | CHAR | BOOL ; @@ -88,6 +89,7 @@ COMMENT: '/*' .*? '*/' -> skip; // types I32: 'i32'; +I64: 'i64'; CHAR: 'ch'; BOOL: 'bool'; diff --git a/include/ast/ast.h b/include/ast/ast.h index 3ed929f..68cec38 100644 --- a/include/ast/ast.h +++ b/include/ast/ast.h @@ -72,11 +72,11 @@ class Expression : public Node { class IntegerLiteral : public Expression { private: - int value; + long long value; public: - explicit IntegerLiteral(int value, Token* token); - int get_value() const; + explicit IntegerLiteral(long long value, TypePtr type, Token* token); + long long get_value() const; void xml(int level) override; }; diff --git a/include/backend/types/integer.h b/include/backend/types/integer.h index 638592f..58752c0 100644 --- a/include/backend/types/integer.h +++ b/include/backend/types/integer.h @@ -4,4 +4,5 @@ namespace integer { mlir::Value create_i32(int value); +mlir::Value create_i64(long long value); } // namespace integer diff --git a/include/shared/context.h b/include/shared/context.h index 2866149..8414ffd 100644 --- a/include/shared/context.h +++ b/include/shared/context.h @@ -19,9 +19,10 @@ extern mlir::MLIRContext context; extern TypePtr ch; extern TypePtr any; extern TypePtr i32; +extern TypePtr i64; extern TypePtr f32; extern TypePtr none; -extern TypePtr t_bool; +extern TypePtr bool_; extern std::vector primitives; diff --git a/include/shared/type/integer.h b/include/shared/type/integer.h index 3a9301f..cf67e13 100644 --- a/include/shared/type/integer.h +++ b/include/shared/type/integer.h @@ -9,3 +9,11 @@ class I32 : public Type { mlir::Type get_mlir() const override; bool is_numeric() const override; }; + +class I64 : public Type { + public: + I64(); + std::string get_specifier() const override; + mlir::Type get_mlir() const override; + bool is_numeric() const override; +}; diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index b8341c0..5241d7b 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -111,7 +111,7 @@ TypePtr ast::Expression::get_type() const { } ast::BooleanLiteral::BooleanLiteral(bool value, Token* token) - : Expression(ctx::t_bool, token) { + : Expression(ctx::bool_, token) { this->value = value; } @@ -135,22 +135,23 @@ char ast::CharacterLiteral::get_value() const { } void ast::CharacterLiteral::xml(int level) { - std::cout << std::string(level * 4, ' ') << "value + std::cout << std::string(level * 4, ' ') << "\n"; } -ast::IntegerLiteral::IntegerLiteral(int value, Token* token) - : Expression(ctx::i32, token) { +ast::IntegerLiteral::IntegerLiteral(long long value, TypePtr type, Token* token) + : Expression(type, token) { + assert(*type == *ctx::i32 || *type == *ctx::i64); this->value = value; } -int ast::IntegerLiteral::get_value() const { +long long ast::IntegerLiteral::get_value() const { return this->value; } void ast::IntegerLiteral::xml(int level) { - std::cout << std::string(level * 4, ' ') << "value - << "\"/>\n"; + std::cout << std::string(level * 4, ' ') + << "<" + type->get_name() + " value=\"" << value << "\"/>\n"; } ast::Variable::Variable(Qualifier qualifier, diff --git a/src/ast/builder.cpp b/src/ast/builder.cpp index 5e40eaf..2f7c9df 100644 --- a/src/ast/builder.cpp +++ b/src/ast/builder.cpp @@ -5,6 +5,7 @@ #include "FusionParser.h" #include "ast/ast.h" #include "ast/builder.h" +#include "errors/errors.h" #include "shared/context.h" #include "shared/type/type.h" @@ -99,16 +100,23 @@ std::any Builder::visitQualifier(FusionParser::QualifierContext* ctx) { std::any Builder::visitLiteralInt(FusionParser::LiteralIntContext* ctx) { Token* token = ctx->INT()->getSymbol(); - int value = 0; + std::string str = ctx->INT()->getText(); try { - value = std::stoi(ctx->INT()->getText()); - } catch (const std::out_of_range& oor) { - std::runtime_error(oor.what()); + int num = std::stoi(str); + auto node = make_shared(num, ctx::i32, token); + return to_node(node); + } catch (const std::out_of_range&) { + try { + long long num = std::stoll(str); + auto node = make_shared(num, ctx::i64, token); + return to_node(node); + } catch (const std::out_of_range&) { + throw SyntaxError(token->getLine(), "number overflowed 64 bits"); + } } - auto node = make_shared(value, token); - return to_node(node); + throw std::runtime_error("failed to parse integer"); } std::any Builder::visitLiteralBool(FusionParser::LiteralBoolContext* ctx) { diff --git a/src/ast/passes/type_check.cpp b/src/ast/passes/type_check.cpp index f6d63e3..95a5b9e 100644 --- a/src/ast/passes/type_check.cpp +++ b/src/ast/passes/type_check.cpp @@ -9,12 +9,17 @@ void TypeCheck::visit_declaration(shared_ptr node) { visit(node->var); visit(node->expr); - Type var = *node->var->get_type(); - Type expr = *node->expr->get_type(); - if (var != expr) { + TypePtr var = node->var->get_type(); + TypePtr expr = node->expr->get_type(); + if (*var == *ctx::i64 && *expr == *ctx::i32) { + node->expr->set_type(ctx::i64); + return; + } + + if (*var != *expr) { throw TypeError(node->token->getLine(), - "mismatched lhs(" + var.get_name() + ") and rhs(" + - expr.get_name() + ") types on declaration"); + "mismatched lhs(" + var->get_name() + ") and rhs(" + + expr->get_name() + ") types on declaration"); } } @@ -96,7 +101,7 @@ void TypeCheck::visit_binary_operator(shared_ptr node) { case ast::BinaryOpType::GTE: check_numeric(lhs, line); check_numeric(rhs, line); - node->set_type(ctx::t_bool); + node->set_type(ctx::bool_); break; case ast::BinaryOpType::ADD: case ast::BinaryOpType::SUB: @@ -112,11 +117,11 @@ void TypeCheck::visit_binary_operator(shared_ptr node) { case ast::BinaryOpType::OR: check_bool(lhs, line); check_bool(rhs, line); - node->set_type(ctx::t_bool); + node->set_type(ctx::bool_); break; case ast::BinaryOpType::EQ: case ast::BinaryOpType::NE: - node->set_type(ctx::t_bool); + node->set_type(ctx::bool_); break; } } @@ -125,17 +130,17 @@ void TypeCheck::visit_unary_operator(shared_ptr node) { visit(node->rhs); size_t line = node->token->getLine(); - Type rhs = *node->get_type(); - if (node->type == ast::UnaryOpType::MINUS && rhs != *ctx::i32) { + TypePtr rhs = node->get_type(); + if (node->type == ast::UnaryOpType::MINUS && !rhs->is_numeric()) { throw TypeError( line, "unary minus only works on numeric types, found type: " + - rhs.get_name()); + rhs->get_name()); } - if (node->type == ast::UnaryOpType::NOT && rhs != *ctx::t_bool) { + if (node->type == ast::UnaryOpType::NOT && *rhs != *ctx::bool_) { throw TypeError(line, "unary minus only works on booleans, found type: " + - rhs.get_name()); + rhs->get_name()); } } @@ -146,7 +151,7 @@ void TypeCheck::check_numeric(TypePtr type, size_t line) { } void TypeCheck::check_bool(TypePtr type, size_t line) { - if (*type != *ctx::t_bool) { + if (*type != *ctx::bool_) { throw TypeError(line, "type(" + type->get_name() + ") is not boolean"); } } diff --git a/src/backend/builtin/print.cpp b/src/backend/builtin/print.cpp index 65a8644..3bd7e60 100644 --- a/src/backend/builtin/print.cpp +++ b/src/backend/builtin/print.cpp @@ -29,7 +29,7 @@ void setupPrintf() { void newline_type_str(TypePtr type) { std::string ty = type->get_specifier() + "\n"; - auto gvalue = mlir::StringRef(ty.c_str(), 4); + auto gvalue = mlir::StringRef(ty.c_str(), ty.size() + 1); auto gtype = mlir::LLVM::LLVMArrayType::get(ctx::ch->get_mlir(), gvalue.size()); diff --git a/src/backend/expressions/arithmetic.cpp b/src/backend/expressions/arithmetic.cpp index d73ff61..6410da7 100644 --- a/src/backend/expressions/arithmetic.cpp +++ b/src/backend/expressions/arithmetic.cpp @@ -36,11 +36,11 @@ mlir::Value arithmetic::mod(mlir::Value lhs, mlir::Value rhs, TypePtr type) { } mlir::Value arithmetic::and_(mlir::Value lhs, mlir::Value rhs, TypePtr type) { - return binop(lhs, rhs, ctx::t_bool); + return binop(lhs, rhs, ctx::bool_); } mlir::Value arithmetic::or_(mlir::Value lhs, mlir::Value rhs, TypePtr type) { - return binop(lhs, rhs, ctx::t_bool); + return binop(lhs, rhs, ctx::bool_); } mlir::Value arithmetic::pow(mlir::Value lhs, mlir::Value rhs, TypePtr type) { @@ -79,7 +79,7 @@ mlir::Value arithmetic::lte(mlir::Value lhs, mlir::Value rhs, TypePtr type) { mlir::Value arithmetic::not_(mlir::Value value) { mlir::Value f = boolean::create_bool(false); - return eq(f, value, ctx::t_bool); + return eq(f, value, ctx::bool_); } mlir::Value arithmetic::negate(mlir::Value value, TypePtr type) { @@ -92,7 +92,7 @@ mlir::Value arithmetic::binary_equality(mlir::Value lhs, TypePtr type, mlir::LLVM::ICmpPredicate predicate) { mlir::Value value = ctx::builder->create( - *ctx::loc, ctx::t_bool->get_mlir(), predicate, lhs, rhs); + *ctx::loc, ctx::bool_->get_mlir(), predicate, lhs, rhs); return value; } diff --git a/src/backend/types/boolean.cpp b/src/backend/types/boolean.cpp index 41f8521..2ef0720 100644 --- a/src/backend/types/boolean.cpp +++ b/src/backend/types/boolean.cpp @@ -3,7 +3,7 @@ mlir::Value boolean::create_bool(bool value) { mlir::Value val = ctx::builder->create( - *ctx::loc, ctx::t_bool->get_mlir(), value); + *ctx::loc, ctx::bool_->get_mlir(), value); return val; } diff --git a/src/backend/types/integer.cpp b/src/backend/types/integer.cpp index c4ee90d..d858d7d 100644 --- a/src/backend/types/integer.cpp +++ b/src/backend/types/integer.cpp @@ -7,3 +7,10 @@ mlir::Value integer::create_i32(int value) { return val; } + +mlir::Value integer::create_i64(long long value) { + mlir::Value val = ctx::builder->create( + *ctx::loc, ctx::i64->get_mlir(), value); + + return val; +} diff --git a/src/backend/visitor.cpp b/src/backend/visitor.cpp index 2f88764..89c0218 100644 --- a/src/backend/visitor.cpp +++ b/src/backend/visitor.cpp @@ -46,7 +46,11 @@ mlir::Value Backend::visit_block(shared_ptr node) { mlir::Value Backend::visit_integer_literal( shared_ptr node) { - return integer::create_i32(node->get_value()); + if (*node->get_type() == *ctx::i32) { + return integer::create_i32(node->get_value()); + } + + return integer::create_i64(node->get_value()); } mlir::Value Backend::visit_character_literal( diff --git a/src/shared/context.cpp b/src/shared/context.cpp index 61962c7..fa8e7bd 100644 --- a/src/shared/context.cpp +++ b/src/shared/context.cpp @@ -14,9 +14,10 @@ std::unique_ptr ctx::module; TypePtr ctx::ch; TypePtr ctx::any; TypePtr ctx::i32; +TypePtr ctx::i64; TypePtr ctx::f32; TypePtr ctx::none; -TypePtr ctx::t_bool; +TypePtr ctx::bool_; std::vector ctx::primitives; @@ -26,16 +27,14 @@ void ctx::initialize_context() { ctx::any = make_shared(); ctx::i32 = make_shared(); + ctx::i64 = make_shared(); ctx::f32 = make_shared(); ctx::none = make_shared(); ctx::ch = make_shared(); - ctx::t_bool = make_shared(); + ctx::bool_ = make_shared(); ctx::primitives = { - ctx::ch, - ctx::i32, - ctx::f32, - ctx::t_bool, + ctx::ch, ctx::i32, ctx::i64, ctx::f32, ctx::bool_, }; module = std::make_unique( diff --git a/src/shared/type/integer.cpp b/src/shared/type/integer.cpp index d38da35..aecceb7 100644 --- a/src/shared/type/integer.cpp +++ b/src/shared/type/integer.cpp @@ -14,3 +14,17 @@ mlir::Type I32::get_mlir() const { bool I32::is_numeric() const { return true; } + +I64::I64() : Type("i64") {} + +std::string I64::get_specifier() const { + return "%ld"; +} + +mlir::Type I64::get_mlir() const { + return ctx::builder->getI64Type(); +} + +bool I64::is_numeric() const { + return true; +} diff --git a/tests/input/declaration/basic.in b/tests/input/declaration/basic.in index d843647..fc4f015 100644 --- a/tests/input/declaration/basic.in +++ b/tests/input/declaration/basic.in @@ -14,5 +14,8 @@ fn main(): i32 { println(t); println(f); + let r: i64 = 10000000000000; + println(r); + return 0; } diff --git a/tests/input/errors/syntax/int_overflow.in b/tests/input/errors/syntax/int_overflow.in new file mode 100644 index 0000000..b26134b --- /dev/null +++ b/tests/input/errors/syntax/int_overflow.in @@ -0,0 +1,4 @@ +fn main(): i32 { + let x: i64 = 100000000000000000000000000000000000; + return 0; +} diff --git a/tests/input/errors/type/int_sizes.in b/tests/input/errors/type/int_sizes.in new file mode 100644 index 0000000..af8869f --- /dev/null +++ b/tests/input/errors/type/int_sizes.in @@ -0,0 +1,4 @@ +fn main(): i32 { + let x: i32 = 10000000000000; + return 0; +} \ No newline at end of file diff --git a/tests/output/declaration/basic.out b/tests/output/declaration/basic.out index a833f4c..b2cfae9 100644 --- a/tests/output/declaration/basic.out +++ b/tests/output/declaration/basic.out @@ -1,3 +1,4 @@ 55a 1 0 +10000000000000 diff --git a/tests/output/errors/syntax/int_overflow.out b/tests/output/errors/syntax/int_overflow.out new file mode 100644 index 0000000..8142565 --- /dev/null +++ b/tests/output/errors/syntax/int_overflow.out @@ -0,0 +1 @@ +SyntaxError on Line 2 \ No newline at end of file diff --git a/tests/output/errors/type/int_sizes.out b/tests/output/errors/type/int_sizes.out new file mode 100644 index 0000000..cae1341 --- /dev/null +++ b/tests/output/errors/type/int_sizes.out @@ -0,0 +1 @@ +TypeError on Line 2 \ No newline at end of file