diff --git a/cpp/src/ast.hpp b/cpp/src/ast.hpp index 9a853fe..e627efe 100644 --- a/cpp/src/ast.hpp +++ b/cpp/src/ast.hpp @@ -41,6 +41,7 @@ struct ast } bool operator==(const bool_literal& rhs) const = default; }; + struct identifier { std::string iden; @@ -51,6 +52,17 @@ struct ast bool operator==(const identifier& rhs) const = default; }; + struct member_access + { + boxed_expression lhs; + std::string rhs; + std::string to_string() const + { + return std::format("member_access({}.{})", lhs->to_string(), rhs); + } + bool operator==(const member_access& rhs) const = default; + }; + struct unary_operator { lex::token op; @@ -145,6 +157,7 @@ struct ast ast::decimal_literal, ast::bool_literal, ast::identifier, + ast::member_access, ast::variable_declaration, ast::function_call, ast::return_statement, @@ -216,7 +229,7 @@ struct ast struct node { - using payload_t = std::variant; + using payload_t = std::variant; payload_t payload = std::monostate{}; srcloc meta = {}; std::vector children = {}; diff --git a/cpp/src/parse.cpp b/cpp/src/parse.cpp index e94b586..7baa91d 100644 --- a/cpp/src/parse.cpp +++ b/cpp/src/parse.cpp @@ -51,6 +51,8 @@ namespace parse bool reduce_from_bool_literal(std::size_t offset); // given an ast::identifier subtree at the offset, try to reduce its surrounding tokens/atoms into something bigger. returns true on success, false otherwise. bool reduce_from_identifier(std::size_t offset); + // given an ast::member_access subtree at the offset, try to reduce its surrounding tokens/atoms into something bigger. returns true on success, false otherwise. + bool reduce_from_member_access(std::size_t offset); // given an ast::variable_declaration subtree at the offset, try to reduce its surrounding tokens/atoms into something bigger. returns true on success, false otherwise. bool reduce_from_variable_declaration(std::size_t offset); // given an ast::function_call subtree at the offset, try to reduce its surrounding tokens/atoms into something bigger. returns true on success, false otherwise. @@ -517,6 +519,19 @@ namespace parse return true; } retr.undo(); + auto dot = retr.retrieve(); + if(dot.has_value() && dot->t == lex::type::dot) + { + if(!retr.avail()){return false;} + auto rhs_iden = retr.retrieve(); + if(!rhs_iden.has_value()) + { + return false; + } + retr.reduce_to(ast::member_access{.lhs = ast::expression{.expr =value, .capped = false}, .rhs = rhs_iden->iden}, meta); + return true; + } + retr.undo(); // getting difficult here... // at some point we need to know whether an identifier should remain an identifier or become an expression @@ -570,6 +585,26 @@ namespace parse return false; } + bool parser_state::reduce_from_member_access(std::size_t offset) + { + retriever retr{*this, offset}; + srcloc meta; + auto value = retr.must_retrieve(&meta); + + if(!retr.avail()){return false;} + bool capped = false; + + auto semicolon = retr.retrieve(); + capped = (semicolon.has_value() && semicolon->t == lex::type::semicolon); + if(!capped) + { + retr.undo(); + } + + retr.reduce_to(ast::expression{.expr = value, .capped = capped}, meta); + return true; + } + bool parser_state::reduce_from_variable_declaration(std::size_t offset) { retriever retr{*this, offset}; @@ -644,6 +679,18 @@ namespace parse return true; } } + else if(tok->t == lex::type::dot) + { + // could be a member access. + if(!retr.avail()){return false;} + auto iden = retr.retrieve(); + if(!iden.has_value()) + { + return false; + } + retr.reduce_to(ast::member_access{.lhs = value, .rhs = iden->iden}, meta); + return true; + } } } // as expressions can either be within a block or standalone, the only way we know for sure its standalone is if its the very first subtree. @@ -1125,6 +1172,10 @@ namespace parse { ret = this->reduce_from_identifier(i); }, + [&](ast::member_access arg) + { + ret = this->reduce_from_member_access(i); + }, [&](ast::variable_declaration arg) { ret = this->reduce_from_variable_declaration(i); diff --git a/cpp/src/semal.cpp b/cpp/src/semal.cpp index ba4c7de..aecfb38 100644 --- a/cpp/src/semal.cpp +++ b/cpp/src/semal.cpp @@ -605,6 +605,23 @@ namespace semal return maybe_function->return_ty; } + type member_access(const data& d, const ast::member_access& payload) + { + type lhs_ty = expression(d, *payload.lhs); + d.assert_that(lhs_ty.is_struct(), std::format("detected use of member-access token `.`. the left-hand-side of the token must be a struct type, which \"{}\" is not.", lhs_ty.name())); + struct_type struct_ty = lhs_ty.as_struct(); + for(std::size_t i = 0; i < struct_ty.data_members.size(); i++) + { + const auto& member = struct_ty.data_members[i]; + if(member.member_name == payload.rhs) + { + return *member.ty; + } + } + d.fatal_error(std::format("struct \"{}\" has no data member named \"{}\"", struct_ty.name, payload.rhs)); + return type::undefined(); + } + type return_statement(const data& d, const ast::return_statement& payload) { const function_t* maybe_parent = d.state.try_find_parent_function(d.tree, d.path); @@ -744,12 +761,10 @@ namespace semal { ret = function_call(d, call); }, - /* [&](ast::member_access mem) { ret = member_access(d, mem); }, - */ [&](ast::expression expr) { ret = expression(d, expr); diff --git a/samples/scratchpad.psy b/samples/scratchpad.psy index c2a0420..330fb48 100644 --- a/samples/scratchpad.psy +++ b/samples/scratchpad.psy @@ -3,21 +3,38 @@ hio : i64 := 64; +nesteddata :: struct +{ + flak : i64; +} + mydata :: struct { member : i64 := 5; + member2 : i64 := 69; + nested : nesteddata; +} +xyz : mydata; +xyz.member; + +get_data :: () -> mydata +{ + ret : mydata; + (ret.nested.flak) = 9; + return ret; } //class :: typedef := mydata; putchar :: (ch : i64) -> u0 := extern; dub :: (val : i64) -> i64 { + get_data().member = 5; //ptr : i8& := __builtin_malloc(123); //defer __builtin_free(ptr); is_cringe : bool := (true == false); val = deref ref val; - val = (val + val); + val = (val + (get_data().member)); v : i64&; val = (val * val * val * (deref v)); deref v = 862; @@ -44,7 +61,7 @@ morb :: (par0 : i64) -> f64 poggers2 : i64; poggers3 : i64; //morb2 :: (par0 : i64) -> u0 := extern; - complicated(poggers, dub(5), 3); + complicated(poggers, dub(5), get_data().member2); complicated(--complicated(1, 2, 3), dub(5), 690); if poggers1 == 59