diff --git a/furc/include/furc/ast/expression.hpp b/furc/include/furc/ast/expression.hpp index d03a954..73b9109 100644 --- a/furc/include/furc/ast/expression.hpp +++ b/furc/include/furc/ast/expression.hpp @@ -114,6 +114,7 @@ enum class unaryop_expression_node_t { PrefixDecrement, /**< Prefix decrement */ PostfixDecrement, /**< Postfix decrement */ Pointerof, /**< Pointerof */ + Sizeof, /**< Sizeof */ }; /** diff --git a/furc/include/furc/front/token.hpp b/furc/include/furc/front/token.hpp index a0bb50d..d648368 100644 --- a/furc/include/furc/front/token.hpp +++ b/furc/include/furc/front/token.hpp @@ -158,6 +158,7 @@ enum class keyword_token { Public, /**< `public` */ Private, /**< `private` */ Pointerof, /**< `pointerof` */ + Sizeof, /**< `sizeof` */ Int32, /**< `int32` */ }; @@ -175,6 +176,7 @@ static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword) case keyword_token::Public: return os << "public"; case keyword_token::Private: return os << "private"; case keyword_token::Pointerof: return os << "pointerof"; + case keyword_token::Sizeof: return os << "sizeof"; case keyword_token::Int32: return os << "int32"; } return os; @@ -193,6 +195,7 @@ static inline std::string operator+(const std::string& str, keyword_token keywor case keyword_token::Public: return str + "public"; case keyword_token::Private: return str + "private"; case keyword_token::Pointerof: return str + "pointerof"; + case keyword_token::Sizeof: return str + "sizeof"; case keyword_token::Int32: return str + "int32"; } return str; diff --git a/furc/src/ast.cpp b/furc/src/ast.cpp index 9fa177e..95bc727 100644 --- a/furc/src/ast.cpp +++ b/furc/src/ast.cpp @@ -38,6 +38,7 @@ std::ostream& operator<<(std::ostream& os, unaryop_expression_node_t type) { case unaryop_expression_node_t::PrefixDecrement: case unaryop_expression_node_t::PostfixDecrement: return os << "--"; case unaryop_expression_node_t::Pointerof: return os << "pointerof"; + case unaryop_expression_node_t::Sizeof: return os << "sizeof"; } return os; } @@ -56,6 +57,7 @@ std::ostream& unary_op_expression_node::print(std::ostream& os) const { case unaryop_expression_node_t::PostfixIncrement: case unaryop_expression_node_t::PostfixDecrement: return os << '(' << *m_node << m_type << ')'; case unaryop_expression_node_t::Pointerof: return os << "pointerof " << *m_node; + case unaryop_expression_node_t::Sizeof: return os << "sizeof " << *m_node; } return os; } diff --git a/furc/src/back/furvm.cpp b/furc/src/back/furvm.cpp index 7399429..b592053 100644 --- a/furc/src/back/furvm.cpp +++ b/furc/src/back/furvm.cpp @@ -59,6 +59,7 @@ static inline furvm::instruction_t op_type(furlang::ir::instruction_t type) { switch (type) { // Unary case furlang::ir::instruction_t::Pointerof: return furvm::instruction_t::Pointerof; + case furlang::ir::instruction_t::Sizeof: return furvm::instruction_t::Sizeof; // Binary case furlang::ir::instruction_t::Add: return furvm::instruction_t::Add; @@ -116,7 +117,8 @@ void furvm_generator::generate_instruction(furvm::mod& mod, mod.bytecode().push_back((var >> 8) & 0xFF); static_assert(sizeof(var) == 2, "sizeof(furvm::variable_t) has changed"); } break; - case furlang::ir::instruction_t::Pointerof: { + case furlang::ir::instruction_t::Pointerof: + case furlang::ir::instruction_t::Sizeof: { mod.bytecode().push_back(static_cast(op_type(instr.type()))); if (ctx.variables.find(instr.destination().reg()) == ctx.variables.end()) { diff --git a/furc/src/front/ir_generator.cpp b/furc/src/front/ir_generator.cpp index 5bb057e..386ec4f 100644 --- a/furc/src/front/ir_generator.cpp +++ b/furc/src/front/ir_generator.cpp @@ -135,6 +135,7 @@ void ir_generator::visit(const ast::var_read_expression_node& node) { static inline furlang::ir::instruction_t unary_op_instruction_t(ast::unaryop_expression_node_t type) { switch (type) { case ast::unaryop_expression_node_t::Pointerof: return furlang::ir::instruction_t::Pointerof; + case ast::unaryop_expression_node_t::Sizeof: return furlang::ir::instruction_t::Sizeof; default: throw std::runtime_error("unimplemented"); } } diff --git a/furc/src/front/lexer.cpp b/furc/src/front/lexer.cpp index 37903c1..1ba946f 100644 --- a/furc/src/front/lexer.cpp +++ b/furc/src/front/lexer.cpp @@ -105,6 +105,7 @@ token_r lexer::next_token() { { "public", keyword_token::Public }, { "private", keyword_token::Private }, { "pointerof", keyword_token::Pointerof }, + { "sizeof", keyword_token::Sizeof }, { "int32", keyword_token::Int32 }, }; diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index 3cd0630..3c405d1 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -323,6 +323,7 @@ static inline std::optional get_unaryop_info(const token_r& token) }; static std::unordered_map s_keywords = { { keyword_token::Pointerof, unaryop_info{ ast::unaryop_expression_node_t::Pointerof, 2 } }, + { keyword_token::Sizeof, unaryop_info{ ast::unaryop_expression_node_t::Sizeof, 2 } }, }; if (token->type == token_t::Keyword) { diff --git a/furc/src/main.cpp b/furc/src/main.cpp index c718354..f5ce2a4 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -23,7 +23,7 @@ int main(void) { while (x < y) { x = x + z; } - print(pointerof x); + print(sizeof x); } )"; furlang::arena arena{}; diff --git a/furlang/include/furlang/ir/instruction.hpp b/furlang/include/furlang/ir/instruction.hpp index e47651d..4c298ab 100644 --- a/furlang/include/furlang/ir/instruction.hpp +++ b/furlang/include/furlang/ir/instruction.hpp @@ -32,6 +32,7 @@ enum class instruction_t { LessEq, /**< Less or equal */ GreaterEq, /**< Greater or equal */ Pointerof, /**< Pointerof */ + Sizeof, /**< Sizeof */ Call, /**< Call */ Branch, /**< Branch */ BranchCond, /**< Conditional branch */ @@ -55,6 +56,7 @@ static inline std::ostream& operator<<(std::ostream& os, instruction_t type) { case instruction_t::LessEq: return os << "lessEq"; case instruction_t::GreaterEq: return os << "greaterEq"; case instruction_t::Pointerof: return os << "pointerof"; + case instruction_t::Sizeof: return os << "sizeof"; case instruction_t::Call: return os << "call"; case instruction_t::Branch: return os << "branch"; case instruction_t::BranchCond: return os << "branchCond"; diff --git a/furvm/include/furvm/instruction.hpp b/furvm/include/furvm/instruction.hpp index 2304560..fdad85c 100644 --- a/furvm/include/furvm/instruction.hpp +++ b/furvm/include/furvm/instruction.hpp @@ -107,6 +107,11 @@ enum class instruction_t : byte { */ Pointerof, + /** + * @brief Pushes a size of popped-off thing onto the stack. + */ + Sizeof, + /** * @brief Pushes a variable onto the stack. * diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index bcbe516..c5c8091 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -175,6 +175,18 @@ void executor::step() { default: throw std::runtime_error("unreachable"); } } break; + case instruction_t::Sizeof: { + auto thing = pop_thing()->resolve(); + auto ptr = push_thing({ *m_context->at("core")->type_at(3), m_context, m_context->thing_alloc() }); + auto type = furvm::thing<>::resolve_type(thing.type(), m_context); + switch (type->t) { + case type_t::Primitive: ptr->get() = static_cast(type->primitive); break; + case type_t::List: ptr->get() = thing.get().size; break; + case type_t::Reference: + case type_t::Import: + default: throw std::runtime_error("unreachable"); + } + } break; case instruction_t::Load: { variable_t variable = static_cast(frame.mod->byte(frame.position)) | (static_cast(frame.mod->byte(frame.position + 1)) << 8);