diff --git a/cpp/src/lex.cpp b/cpp/src/lex.cpp index d8551a8..46f42c6 100644 --- a/cpp/src/lex.cpp +++ b/cpp/src/lex.cpp @@ -390,6 +390,11 @@ namespace lex bool breaks_word(const tokenise_state& state, std::string_view str) { + if(str.starts_with(" const")) + { + // don't break on a space if its immediately followed by const. + return false; + } if(state.in_integer_literal() && str.starts_with(".")) { return false; diff --git a/cpp/src/semal.cpp b/cpp/src/semal.cpp index 3f146fe..d1c1dfd 100644 --- a/cpp/src/semal.cpp +++ b/cpp/src/semal.cpp @@ -45,20 +45,29 @@ namespace semal { type ret = type::undefined(); std::string cur_type = ""; - auto check_const = [&cur_type, &ret, &type_name](){if(type_name == "const"){ret.qualifiers = static_cast(static_cast(ret.qualifiers) | qualifier_const);}}; for(std::size_t i = 0; i < type_name.size(); i++) { - char c = type_name[i]; - if(c == '&') + if(std::string_view(type_name.data() + i).starts_with(" const")) { - check_const(); - ret = get_type_from_name(cur_type).pointer_to(); - cur_type = ""; + if(ret.is_undefined()) + { + ret = get_type_from_name(cur_type); + } + ret.qualifiers = (type_qualifier)((int)ret.qualifiers | qualifier_const); + i += sizeof(" const") - 2; + continue; } - else if(c == ' ') + char c = type_name[i]; + if(c == '&') { - check_const(); - ret = get_type_from_name(cur_type); + if(ret.is_undefined()) + { + ret = get_type_from_name(cur_type).pointer_to(); + } + else + { + ret = ret.pointer_to(); + } cur_type = ""; } else @@ -68,17 +77,6 @@ namespace semal } if(cur_type.size()) { - std::string without_qualifiers = cur_type; - auto iter = without_qualifiers.find("const"); - if(iter != std::string::npos) - { - without_qualifiers.erase(iter, sizeof("const") - 1); // -1 as sizeof includes null terminator - } - type_qualifier quals = iter != std::string::npos ? qualifier_const : qualifier_none; - if(!ret.is_undefined()) - { - ret.qualifiers = quals; - } if(ret.is_undefined()) { // try a struct. @@ -86,7 +84,7 @@ namespace semal { if(cur_type == struct_name) { - ret = type::from_struct(structdata.ty, quals); + ret = type::from_struct(structdata.ty); break; } } @@ -98,7 +96,7 @@ namespace semal { if(cur_type == primitive_type_names[i]) { - ret = type::from_primitive(static_cast(i), quals); + ret = type::from_primitive(static_cast(i)); break; } } @@ -550,6 +548,7 @@ namespace semal switch(payload.op.t) { case lex::type::operator_equals: + d.assert_that(!lhs.is_const(), std::format("lhs of assignment is const: \"{}\"", lhs.name())); d.assert_that(lhs == rhs, std::format("cannot assign from type \"{}\" to a type \"{}\"", lhs.name(), rhs.name())); return rhs; break; @@ -701,6 +700,7 @@ namespace semal const auto& ty = d.state.get_type_from_name(payload.type_name); d.assert_that(!ty.is_undefined(), std::format("undefined type \"{}\"", payload.type_name)); + d.assert_that(payload.type_name == ty.name(), std::format("parse-type-from-string error. input string: \"{}\". output type.name(): \"{}\"", payload.type_name, ty.name())); d.state.register_local_variable ({ .ty = ty, @@ -711,7 +711,7 @@ namespace semal if(payload.initialiser.has_value()) { type expr_ty = expression(d, *payload.initialiser.value()); - d.assert_that(expr_ty == ty, std::format("initialiser of variable \"{}\" is of type \"{}\", which does not match the variable's type of \"{}\". perhaps you forgot to insert a cast?", payload.var_name, expr_ty.name(), ty.name())); + d.assert_that(expr_ty.without_qualifiers() == ty.without_qualifiers(), std::format("initialiser of variable \"{}\" is of type \"{}\", which does not match the variable's type of \"{}\". perhaps you forgot to insert a cast?", payload.var_name, expr_ty.name(), ty.name())); } return ty; } diff --git a/cpp/src/type.cpp b/cpp/src/type.cpp index cff0576..f02d6da 100644 --- a/cpp/src/type.cpp +++ b/cpp/src/type.cpp @@ -146,6 +146,11 @@ bool type::is_void() const && !this->is_pointer(); } +bool type::is_const() const +{ + return this->qualifiers & qualifier_const; +} + primitive_type type::as_primitive() const { diag::assert_that(this->is_primitive(), error_code::ice, "attempt to resolve non-primitive type \"{}\" as a primitive", this->name()); @@ -181,10 +186,6 @@ std::string type::name() const } else { - if(qualstr.size() && qualstr.front() == ' ') - { - qualstr.erase(qualstr.begin()); - } ret = std::format("{}&{}", std::get>(this->ty)->name(), qualstr); } @@ -207,6 +208,13 @@ type type::pointer_to(type_qualifier quals) const }; } +type type::without_qualifiers() const +{ + type ret = *this; + ret.qualifiers = qualifier_none; + return ret; +} + /*static*/type type::undefined() { return diff --git a/cpp/src/type.hpp b/cpp/src/type.hpp index b1e6bf6..a8efa4b 100644 --- a/cpp/src/type.hpp +++ b/cpp/src/type.hpp @@ -93,6 +93,8 @@ struct type bool is_floating_point_type() const; bool is_void() const; + bool is_const() const; + primitive_type as_primitive() const; struct_type as_struct() const; @@ -100,6 +102,7 @@ struct type type dereference() const; type pointer_to(type_qualifier quals = qualifier_none) const; + type without_qualifiers() const; static type undefined(); static type from_primitive(primitive_type t, type_qualifier quals = qualifier_none); diff --git a/samples/scratchpad.psy b/samples/scratchpad.psy index df3424f..0e7ddef 100644 --- a/samples/scratchpad.psy +++ b/samples/scratchpad.psy @@ -28,6 +28,11 @@ get_data :: () -> mydata putchar :: (ch : i8) -> u0 := extern; dub :: (val : i64) -> i64 { + vvptr : i64&& const; + deref vvptr = (55@i64&); + vv : i64 := 5; + vv = 50; + get_data().member = 5; ptr : i8& := __builtin_malloc(123@u64); longptr : i64& := (ptr@i64&);