Skip to content

Commit

Permalink
64 Bit Integers (#44)
Browse files Browse the repository at this point in the history
* add i64

* add extra type check tests
  • Loading branch information
jackparsonss committed Jul 2, 2024
1 parent 6ebe5f3 commit d1c85ae
Show file tree
Hide file tree
Showing 21 changed files with 109 additions and 45 deletions.
4 changes: 3 additions & 1 deletion grammar/Fusion.g4
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ expr
qualifier: CONST | LET;

type
: I32
: I32
| I64
| CHAR
| BOOL
;
Expand Down Expand Up @@ -88,6 +89,7 @@ COMMENT: '/*' .*? '*/' -> skip;

// types
I32: 'i32';
I64: 'i64';
CHAR: 'ch';
BOOL: 'bool';

Expand Down
6 changes: 3 additions & 3 deletions include/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
1 change: 1 addition & 0 deletions include/backend/types/integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

namespace integer {
mlir::Value create_i32(int value);
mlir::Value create_i64(long long value);
} // namespace integer
3 changes: 2 additions & 1 deletion include/shared/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypePtr> primitives;

Expand Down
8 changes: 8 additions & 0 deletions include/shared/type/integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
15 changes: 8 additions & 7 deletions src/ast/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -135,22 +135,23 @@ char ast::CharacterLiteral::get_value() const {
}

void ast::CharacterLiteral::xml(int level) {
std::cout << std::string(level * 4, ' ') << "<ch value=\"" << this->value
std::cout << std::string(level * 4, ' ') << "<ch value=\"" << value
<< "\"/>\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, ' ') << "<i32 value=\"" << this->value
<< "\"/>\n";
std::cout << std::string(level * 4, ' ')
<< "<" + type->get_name() + " value=\"" << value << "\"/>\n";
}

ast::Variable::Variable(Qualifier qualifier,
Expand Down
20 changes: 14 additions & 6 deletions src/ast/builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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<ast::IntegerLiteral>(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<ast::IntegerLiteral>(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<ast::IntegerLiteral>(value, token);
return to_node(node);
throw std::runtime_error("failed to parse integer");
}

std::any Builder::visitLiteralBool(FusionParser::LiteralBoolContext* ctx) {
Expand Down
33 changes: 19 additions & 14 deletions src/ast/passes/type_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ void TypeCheck::visit_declaration(shared_ptr<ast::Declaration> 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");
}
}

Expand Down Expand Up @@ -96,7 +101,7 @@ void TypeCheck::visit_binary_operator(shared_ptr<ast::BinaryOperator> 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:
Expand All @@ -112,11 +117,11 @@ void TypeCheck::visit_binary_operator(shared_ptr<ast::BinaryOperator> 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;
}
}
Expand All @@ -125,17 +130,17 @@ void TypeCheck::visit_unary_operator(shared_ptr<ast::UnaryOperator> 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());
}
}

Expand All @@ -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");
}
}
2 changes: 1 addition & 1 deletion src/backend/builtin/print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
8 changes: 4 additions & 4 deletions src/backend/expressions/arithmetic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<mlir::LLVM::AndOp>(lhs, rhs, ctx::t_bool);
return binop<mlir::LLVM::AndOp>(lhs, rhs, ctx::bool_);
}

mlir::Value arithmetic::or_(mlir::Value lhs, mlir::Value rhs, TypePtr type) {
return binop<mlir::LLVM::OrOp>(lhs, rhs, ctx::t_bool);
return binop<mlir::LLVM::OrOp>(lhs, rhs, ctx::bool_);
}

mlir::Value arithmetic::pow(mlir::Value lhs, mlir::Value rhs, TypePtr type) {
Expand Down Expand Up @@ -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) {
Expand All @@ -92,7 +92,7 @@ mlir::Value arithmetic::binary_equality(mlir::Value lhs,
TypePtr type,
mlir::LLVM::ICmpPredicate predicate) {
mlir::Value value = ctx::builder->create<mlir::LLVM::ICmpOp>(
*ctx::loc, ctx::t_bool->get_mlir(), predicate, lhs, rhs);
*ctx::loc, ctx::bool_->get_mlir(), predicate, lhs, rhs);

return value;
}
Expand Down
2 changes: 1 addition & 1 deletion src/backend/types/boolean.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

mlir::Value boolean::create_bool(bool value) {
mlir::Value val = ctx::builder->create<mlir::LLVM::ConstantOp>(
*ctx::loc, ctx::t_bool->get_mlir(), value);
*ctx::loc, ctx::bool_->get_mlir(), value);

return val;
}
7 changes: 7 additions & 0 deletions src/backend/types/integer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<mlir::LLVM::ConstantOp>(
*ctx::loc, ctx::i64->get_mlir(), value);

return val;
}
6 changes: 5 additions & 1 deletion src/backend/visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ mlir::Value Backend::visit_block(shared_ptr<ast::Block> node) {

mlir::Value Backend::visit_integer_literal(
shared_ptr<ast::IntegerLiteral> 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(
Expand Down
11 changes: 5 additions & 6 deletions src/shared/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ std::unique_ptr<mlir::ModuleOp> 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<TypePtr> ctx::primitives;

Expand All @@ -26,16 +27,14 @@ void ctx::initialize_context() {

ctx::any = make_shared<Any>();
ctx::i32 = make_shared<I32>();
ctx::i64 = make_shared<I64>();
ctx::f32 = make_shared<F32>();
ctx::none = make_shared<None>();
ctx::ch = make_shared<Character>();
ctx::t_bool = make_shared<Boolean>();
ctx::bool_ = make_shared<Boolean>();

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<mlir::ModuleOp>(
Expand Down
14 changes: 14 additions & 0 deletions src/shared/type/integer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
3 changes: 3 additions & 0 deletions tests/input/declaration/basic.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ fn main(): i32 {
println(t);
println(f);

let r: i64 = 10000000000000;
println(r);

return 0;
}
4 changes: 4 additions & 0 deletions tests/input/errors/syntax/int_overflow.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main(): i32 {
let x: i64 = 100000000000000000000000000000000000;
return 0;
}
4 changes: 4 additions & 0 deletions tests/input/errors/type/int_sizes.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main(): i32 {
let x: i32 = 10000000000000;
return 0;
}
1 change: 1 addition & 0 deletions tests/output/declaration/basic.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
55a
1
0
10000000000000
1 change: 1 addition & 0 deletions tests/output/errors/syntax/int_overflow.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SyntaxError on Line 2
1 change: 1 addition & 0 deletions tests/output/errors/type/int_sizes.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TypeError on Line 2

0 comments on commit d1c85ae

Please sign in to comment.