diff options
28 files changed, 281 insertions, 232 deletions
diff --git a/boot/symbol.cc b/boot/symbol.cc index e247bdb..4828070 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -809,7 +809,6 @@ namespace elna::boot { return checked.get<pointer_type>() != nullptr || checked.get<procedure_type>() != nullptr - || checked.get<parameter_type>() != nullptr || is_primitive_type(checked, "Pointer"); } diff --git a/boot/type_check.cc b/boot/type_check.cc index 42e7227..82c910f 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -137,11 +137,6 @@ namespace elna::boot return "Type parameter '" + payload.parameter + "' of '" + this->generic_name + "' is not used"; } - else if constexpr (std::is_same_v<T, argument_not_pointer>) - { - return "Type '" + payload.actual.to_string() + "' cannot be a type argument of '" - + this->generic_name + "', it is not a pointer type"; - } else if constexpr (std::is_same_v<T, argument_not_scalar>) { return "Type '" + payload.actual.to_string() + "' cannot be a type argument of '" @@ -379,7 +374,10 @@ namespace elna::boot */ static std::optional<type> find_opaque_type(const type& checked) { - if (resolve_underlying_type(checked).get<extern_type>() != nullptr) + const type underlying = resolve_underlying_type(checked); + + if (underlying.get<extern_type>() != nullptr + || underlying.get<parameter_type>() != nullptr) { return checked; } @@ -935,27 +933,59 @@ namespace elna::boot const std::shared_ptr<alias_type> unresolved_type = this->bag.lookup(declaration->identifier.name())->is_type()->symbol.get<alias_type>(); - if (const auto generic = unresolved_type->referent.get<generic_type>()) + type referent = unresolved_type->referent; + if (const auto generic = referent.get<generic_type>()) { check_parameters_used(declaration->position(), declaration->identifier.name(), generic->parameters, generic->referent); - return; + referent = generic->referent; } - const type referent = resolve_aliases(unresolved_type->referent); + referent = resolve_aliases(referent); if (const auto record = referent.get<record_type>()) { - for (const auto& [field_name, field] : record->fields) + const record_type_expression *record_expression = declaration->underlying_type().is_record(); + + if (record_expression != nullptr) { - if (const auto opaque = find_opaque_type(field.field_type)) + for (const field_declaration& field : record_expression->fields) { - add_error<type_requirement_error>(declaration->position(), - opaque.value(), type_requirement_error::kind::opaque_field); + if (field.first.empty()) + { + continue; + } + const auto field_entry = record->fields.find(field.first.front().name()); + + if (field_entry == record->fields.end()) + { + continue; + } + if (const auto opaque = find_opaque_type(field_entry->second.field_type)) + { + add_error<type_requirement_error>(field.second->position(), + opaque.value(), type_requirement_error::kind::opaque_field); + } + else if (has_zero_size(field_entry->second.field_type, this->target)) + { + add_error<type_requirement_error>(field.second->position(), + field_entry->second.field_type, type_requirement_error::kind::zero_sized); + } } - else if (has_zero_size(field.field_type, this->target)) + } + else + { + for (const auto& [field_name, field] : record->fields) { - add_error<type_requirement_error>(declaration->position(), - field.field_type, type_requirement_error::kind::zero_sized); + if (const auto opaque = find_opaque_type(field.field_type)) + { + add_error<type_requirement_error>(declaration->position(), + opaque.value(), type_requirement_error::kind::opaque_field); + } + else if (has_zero_size(field.field_type, this->target)) + { + add_error<type_requirement_error>(declaration->position(), + field.field_type, type_requirement_error::kind::zero_sized); + } } } } @@ -1137,10 +1167,17 @@ namespace elna::boot } else if (const auto left_pointer = left.get<pointer_type>()) { - const std::shared_ptr<pointer_type> right_pointer = right.get<pointer_type>(); + if (is_primitive_type(right, "Pointer")) + { + return true; + } + else + { + const std::shared_ptr<pointer_type> right_pointer = right.get<pointer_type>(); - return right_pointer != nullptr - && bind_arguments(parameters, bindings, left_pointer->base, right_pointer->base); + return right_pointer != nullptr + && bind_arguments(parameters, bindings, left_pointer->base, right_pointer->base); + } } else if (const auto left_slice = left.get<slice_type>()) { @@ -1227,7 +1264,7 @@ namespace elna::boot { return argument_rule::mutable_scalar; } - return argument_rule::pointer; + return argument_rule::opaque; } void type_analysis_visitor::check_arguments(const named_expression& reference, @@ -1241,18 +1278,13 @@ namespace elna::boot } const type underlying = resolve_underlying_type(argument); - if (rule != argument_rule::scalar + if (rule == argument_rule::mutable_scalar && resolve_aliases(argument).get<constant_type>() != nullptr) { add_error<generic_error>(reference.position(), reference.name, generic_error::constant_argument{ argument }); } - else if (rule == argument_rule::pointer && !is_any_pointer_type(underlying)) - { - add_error<generic_error>(reference.position(), reference.name, - generic_error::argument_not_pointer{ argument }); - } - else if (rule != argument_rule::pointer && !is_scalar_type(underlying)) + else if (rule != argument_rule::opaque && !is_scalar_type(underlying)) { add_error<generic_error>(reference.position(), reference.name, generic_error::argument_not_scalar{ argument }); @@ -1308,7 +1340,7 @@ namespace elna::boot } else { - check_arguments(*expression, expression->argument_types, argument_rule::pointer); + check_arguments(*expression, expression->argument_types, argument_rule::opaque); } } else if (std::shared_ptr<generic_type> const generic = unwrap_generic(denoted)) @@ -1619,12 +1651,18 @@ namespace elna::boot const type resolved_base = resolve_underlying_type(expression->base().type_decoration); - if (resolved_base.get<parameter_type>() != nullptr) + if (const auto pointer = resolved_base.get<pointer_type>()) { - add_error<type_requirement_error>(expression->position(), expression->base().type_decoration, - type_requirement_error::kind::dereference_of_parameter); + if (const auto opaque = find_opaque_type(pointer->base)) + { + if (opaque->get<parameter_type>() != nullptr) + { + add_error<type_requirement_error>(expression->position(), *opaque, + type_requirement_error::kind::dereference_of_parameter); + } + } } - else if (resolved_base.get<pointer_type>() == nullptr) + else { add_error<type_requirement_error>(expression->position(), expression->base().type_decoration, type_requirement_error::kind::dereference_of_non_pointer); diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc index fc43ebe..643b988 100644 --- a/gcc/gcc/elna-builtins.cc +++ b/gcc/gcc/elna-builtins.cc @@ -266,6 +266,10 @@ namespace elna::gcc } else if (const auto reference = type.get<boot::pointer_type>()) { + if (boot::resolve_underlying_type(reference->base).get<boot::parameter_type>() != nullptr) + { + return elna_pointer_type_node; + } return build_pointer_type(get_inner_alias(reference->base, symbols, placeholder)); } else if (const auto reference = type.get<boot::array_type>()) @@ -304,7 +308,7 @@ namespace elna::gcc } else if (type.get<boot::parameter_type>() != nullptr) { - return elna_pointer_type_node; + return error_mark_node; } else if (const auto reference = type.get<boot::instantiated_type>()) { diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index 31d5c45..705cb29 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -225,10 +225,10 @@ namespace elna::boot /** * Type parameter of a generic declaration. * - * It denotes an unknown pointer type chosen at instantiation, so it is - * usable wherever a pointer is, and erases to a pointer in the backend. - * Each declaration gets fresh parameters; two parameters spelled alike in - * different declarations never compare equal. + * It denotes an unknown opaque type chosen at instantiation, so it is + * usable only behind a pointer (^T), and ^T erases to a pointer in the + * backend. Each declaration gets fresh parameters; two parameters spelled + * alike in different declarations never compare equal. */ struct parameter_type { diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h index 5e4f792..5a2d7f1 100644 --- a/include/elna/boot/type_check.h +++ b/include/elna/boot/type_check.h @@ -177,10 +177,6 @@ namespace elna::boot { std::string parameter; }; - struct argument_not_pointer - { - type actual; - }; struct argument_not_scalar { type actual; @@ -200,7 +196,7 @@ namespace elna::boot }; using payload_type = std::variant<not_generic, unused_parameter, - argument_not_pointer, argument_not_scalar, constant_argument, + argument_not_scalar, constant_argument, uninferrable_parameter, shape_mismatch>; generic_error(const source_position position, const std::string& generic_name, @@ -216,14 +212,13 @@ namespace elna::boot /** * What a generic declaration accepts as a type argument. * - * An erased generic takes a pointer, because that is what its single - * compiled body knows how to move. A builtin has no body to erase, so it - * takes whatever it can load or store, and only a reading one tolerates a - * constant. + * An erased generic takes an opaque pointee, because it is only used + * behind a pointer. A builtin has no body to erase, so it takes whatever + * it can load or store, and only a reading one tolerates a constant. */ enum class argument_rule { - pointer, + opaque, scalar, mutable_scalar }; diff --git a/source/command_line_interface.elna b/source/command_line_interface.elna index 511d6a0..1318e67 100644 --- a/source/command_line_interface.elna +++ b/source/command_line_interface.elna @@ -23,7 +23,7 @@ var parsed: Bool begin i := 1; - result := malloc(#size(CommandLine)); + result := malloc#[CommandLine](#size(CommandLine)); result^.lex := false; result^.parse := false; result^.input := nil; diff --git a/source/common.elna b/source/common.elna index 4579a67..428c4ec 100644 --- a/source/common.elna +++ b/source/common.elna @@ -14,15 +14,15 @@ type end_location: ElnaLocation end -proc write*(fd: Int; buf: Pointer; Word: Int) -> Int +proc write*#[T](fd: Int; buf: ^const T; size: Word) -> Int extern proc write_s*(value: []const Word8) - write(1, cast(value.ptr: Pointer), cast(value.length: Int)) + write(1, value.ptr, value.length) return proc write_z*(value: ^Word8) - write(1, cast(value: Pointer), cast(strlen(value): Int)) + write(1, value, strlen(value)) return proc write_b*(value: Bool) diff --git a/source/cstdio.elna b/source/cstdio.elna index e69d81a..928c7e1 100644 --- a/source/cstdio.elna +++ b/source/cstdio.elna @@ -29,10 +29,10 @@ extern proc fflush*(stream: ^FILE) -> Int extern -proc fread*(ptr: Pointer; size: Word; nmemb: Word; stream: ^FILE) -> Word +proc fread*#[T](ptr: ^T; size: Word; nmemb: Word; stream: ^FILE) -> Word extern -proc fwrite*(ptr: const Pointer; size: Word; nitems: Word; stream: ^FILE) -> Word +proc fwrite*#[T](ptr: ^const T; size: Word; nitems: Word; stream: ^FILE) -> Word extern proc fputc*(c: Int; stream: ^FILE) -> Word @@ -47,13 +47,13 @@ extern proc putchar*(c: Int) -> Int extern -proc sprintf*(str: Pointer; format: ^const Word8; number: Word) -> Int +proc sprintf*(str: ^Word8; format: ^const Word8) #{varargs} -> Int extern -proc fprintf*(stream: Pointer; format: ^const Word8; number: Word) -> Int +proc fprintf*(stream: ^FILE; format: ^const Word8) #{varargs} -> Int extern -proc fdopen*(fildes: Int; mode: ^const Word8) -> Pointer +proc fdopen*(fildes: Int; mode: ^const Word8) -> ^FILE extern end. diff --git a/source/cstdlib.elna b/source/cstdlib.elna index 51f8ea0..10a4d80 100644 --- a/source/cstdlib.elna +++ b/source/cstdlib.elna @@ -3,16 +3,16 @@ obtain one at https://mozilla.org/MPL/2.0/. *) module -proc malloc*(size: Word) -> Pointer +proc malloc*#[T](size: Word) -> ^T extern -proc free*(ptr: Pointer) +proc free*#[T](ptr: ^T) extern -proc calloc*(nmemb: Word; size: Word) -> Pointer +proc calloc*#[T](nmemb: Word; size: Word) -> ^T extern -proc realloc*(ptr: Pointer; size: Word) -> Pointer +proc realloc*#[T](ptr: ^T; size: Word) -> ^T extern proc atoi*(str: ^Word8) -> Int diff --git a/source/cstring.elna b/source/cstring.elna index dcf9e6f..3973573 100644 --- a/source/cstring.elna +++ b/source/cstring.elna @@ -3,13 +3,13 @@ obtain one at https://mozilla.org/MPL/2.0/. *) module -proc memset*(ptr: Pointer; c: Int; n: Word) -> ^Word8 +proc memset*#[T](ptr: ^T; c: Int; n: Word) -> ^Word8 extern -proc memcpy*(dst: Pointer; src: const Pointer; n: Word) +proc memcpy*#[T](dst: ^T; src: ^const T; n: Word) extern -proc memcmp*(s1, s2: const Pointer; n: Word) -> Int +proc memcmp*#[T](s1, s2: ^const T; n: Word) -> Int extern proc strcmp*(s1: ^const Word8; s2: ^const Word8) -> Int diff --git a/source/lexer.elna b/source/lexer.elna index bf1c449..370c24d 100644 --- a/source/lexer.elna +++ b/source/lexer.elna @@ -528,7 +528,7 @@ proc elna_lexer_token_create(kind: ElnaLexerKind; position: ^ElnaPosition) -> ^E var result: ^ElnaLexerToken begin - result := malloc(#size(ElnaLexerToken)); + result := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); result^.kind := kind; result^.position := position^ return result @@ -640,7 +640,7 @@ var character: Word8 result: ^ElnaLexerToken begin - result := malloc(#size(ElnaLexerToken)); + result := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); character := start_position^; if character = ';' then @@ -722,7 +722,7 @@ begin token := elna_lexer_classify_single(cursor^.start, @cursor^.position) elsif action_to_perform = ElnaLexerAction.eof then - token := malloc(#size(ElnaLexerToken)); + token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); token^.kind := ElnaLexerKind.eof elsif action_to_perform = ElnaLexerAction.finalize then token := elna_lexer_classify_finalize(cursor^.start, @cursor^.position) diff --git a/source/main.elna b/source/main.elna index adac5ac..26853c3 100644 --- a/source/main.elna +++ b/source/main.elna @@ -14,17 +14,17 @@ type index: Word end StringBuffer* = record - data: Pointer; + data: ^Word8; size: Word; capacity: Word end - SourceCode = record + SourceCode#[T] = record position: ElnaLocation; - input: Pointer; - empty: proc(stream: Pointer) -> Bool; - advance: proc(stream: Pointer); - head: proc(stream: Pointer) -> Word8 + input: ^T; + empty: proc(stream: ^T) -> Bool; + advance: proc(stream: ^T); + head: proc(stream: ^T) -> Word8 end Tokenizer* = record length: Word; @@ -34,14 +34,11 @@ type (* Standard procedures. *) -proc reallocarray(ptr: Pointer; n: Word; size: Word) -> Pointer -return realloc(ptr, n * size) - proc string_dup(origin: []const Word8) -> []const Word8 var copy: ^Word8 begin - copy := malloc(origin.length); + copy := malloc#[Word8](origin.length); strncpy(copy, origin.ptr, origin.length) return copy[1 to origin.length] @@ -50,7 +47,7 @@ var result: StringBuffer begin result.capacity := 64u; - result.data := malloc(result.capacity); + result.data := malloc#[Word8](result.capacity); result.size := 0u return result @@ -89,60 +86,46 @@ begin file_handle := fopen(filename, "rb\0".ptr); if file_handle <> nil then - result := malloc(#size(SourceFile)); + result := malloc#[SourceFile](#size(SourceFile)); result^.handle := file_handle; result^.size := 0u; result^.index := 1u end return result -proc source_file_empty(source_input: Pointer) -> Bool -var - source_file: ^SourceFile -begin - source_file := cast(source_input: ^SourceFile); - - if source_file^.index > source_file^.size then - source_file^.size := fread(cast(@source_file^.buffer: Pointer), 1u, 1024u, source_file^.handle); - source_file^.index := 1u +proc source_file_empty(source_input: ^SourceFile) -> Bool + if source_input^.index > source_input^.size then + source_input^.size := fread(source_input^.buffer.ptr, 1u, 1024u, source_input^.handle); + source_input^.index := 1u end -return source_file^.size = 0u +return source_input^.size = 0u -proc source_file_head(source_input: Pointer) -> Word8 -var - source_file: ^SourceFile -begin - source_file := cast(source_input: ^SourceFile) -return source_file^.buffer[source_file^.index] - -proc source_file_advance(source_input: Pointer) -var - source_file: ^SourceFile -begin - source_file := cast(source_input: ^SourceFile); +proc source_file_head(source_input: ^SourceFile) -> Word8 +return source_input^.buffer[source_input^.index] - source_file^.index := source_file^.index + 1u +proc source_file_advance(source_input: ^SourceFile) + source_input^.index := source_input^.index + 1u return -proc source_code_empty(source_code: ^SourceCode) -> Bool +proc source_code_empty#[T](source_code: ^SourceCode#[T]) -> Bool return source_code^.empty(source_code^.input) -proc source_code_head(source_code: SourceCode) -> Word8 +proc source_code_head#[T](source_code: SourceCode#[T]) -> Word8 return source_code.head(source_code.input) -proc source_code_advance(source_code: ^SourceCode) +proc source_code_advance#[T](source_code: ^SourceCode#[T]) begin source_code^.advance(source_code^.input); source_code^.position.column := source_code^.position.column return -proc source_code_break(source_code: ^SourceCode) +proc source_code_break#[T](source_code: ^SourceCode#[T]) begin source_code^.position.line := source_code^.position.line + 1u; source_code^.position.column := 0u return -proc source_code_expect(source_code: ^SourceCode; expected: Word8) -> Bool +proc source_code_expect#[T](source_code: ^SourceCode#[T]; expected: Word8) -> Bool return ~source_code_empty(source_code) & source_code_head(source_code^) = expected (* @@ -187,7 +170,7 @@ begin return successful (* Skip spaces. *) -proc lexer_spaces(source_code: ^SourceCode) +proc lexer_spaces#[T](source_code: ^SourceCode#[T]) var current: Word8 begin @@ -205,7 +188,7 @@ return proc lexer_is_ident(char: Word8) -> Bool return isalnum(cast(char: Int)) <> 0 or char = '_' -proc lexer_identifier(source_code: ^SourceCode; token_content: ^StringBuffer) +proc lexer_identifier#[T](source_code: ^SourceCode#[T]; token_content: ^StringBuffer) var content_length: Word begin @@ -215,7 +198,7 @@ begin end return -proc lexer_comment(source_code: ^SourceCode; token_content: ^StringBuffer) -> Bool +proc lexer_comment#[T](source_code: ^SourceCode#[T]; token_content: ^StringBuffer) -> Bool var trailing: Word begin @@ -236,7 +219,7 @@ begin end return trailing = 2u -proc lexer_character(source_code: ^SourceCode; token_content: ^Word8) -> Bool +proc lexer_character#[T](source_code: ^SourceCode#[T]; token_content: ^Word8) -> Bool var successful: Bool begin @@ -257,7 +240,7 @@ begin end return successful -proc lexer_string(source_code: ^SourceCode; token_content: ^StringBuffer) -> Bool +proc lexer_string#[T](source_code: ^SourceCode#[T]; token_content: ^StringBuffer) -> Bool var token_end, constructed_string: ^Word8 token_length: Word @@ -279,7 +262,7 @@ begin end return is_valid -proc lexer_number(source_code: ^SourceCode; token_content: ^Int) +proc lexer_number#[T](source_code: ^SourceCode#[T]; token_content: ^Int) begin token_content^ := 0; @@ -296,81 +279,81 @@ var current_token: ^ElnaLexerToken begin if token_content = "if" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._if elsif token_content = "then" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._then elsif token_content = "else" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._else elsif token_content = "elsif" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._elsif elsif token_content = "while" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._while elsif token_content = "do" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._do elsif token_content = "proc" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._proc elsif token_content = "begin" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._begin elsif token_content = "end" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._end elsif token_content = "extern" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._extern elsif token_content = "const" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._const elsif token_content = "var" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._var elsif token_content = "case" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._case elsif token_content = "of" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._of elsif token_content = "type" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._type elsif token_content = "record" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._record elsif token_content = "true" then - current_token := malloc(#size(ElnaLexerBooleanToken)); + current_token := malloc#[ElnaLexerBooleanToken](#size(ElnaLexerBooleanToken)); current_token^.kind := ElnaLexerKind.boolean; cast(current_token: ^ElnaLexerBooleanToken)^.value := true elsif token_content = "false" then - current_token := malloc(#size(ElnaLexerBooleanToken)); + current_token := malloc#[ElnaLexerBooleanToken](#size(ElnaLexerBooleanToken)); current_token^.kind := ElnaLexerKind.boolean; cast(current_token: ^ElnaLexerBooleanToken)^.value := false elsif token_content = "nil" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.null elsif token_content = "or" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._or elsif token_content = "return" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._return elsif token_content = "cast" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._cast elsif token_content = "defer" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._defer elsif token_content = "import" then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind._import else - current_token := malloc(#size(ElnaLexerStringToken)); + current_token := malloc#[ElnaLexerStringToken](#size(ElnaLexerStringToken)); current_token^.kind := ElnaLexerKind.identifier; cast(current_token: ^ElnaLexerStringToken)^.value := string_dup(token_content) end @@ -381,13 +364,13 @@ var new_length: Word begin new_length := lexer^.length + 1u; - lexer^.data := cast(reallocarray(cast(lexer^.data: Pointer), new_length, #size(Pointer)): ^^ElnaLexerToken); + lexer^.data := realloc#[^ElnaLexerToken](lexer^.data, new_length * #size(^ElnaLexerToken)); (lexer^.data + lexer^.length)^ := token; lexer^.length := new_length return (* Read the next token from the input. *) -proc lexer_next(source_code: SourceCode; token_buffer: ^StringBuffer) -> ^ElnaLexerToken +proc lexer_next#[T](source_code: SourceCode#[T]; token_buffer: ^StringBuffer) -> ^ElnaLexerToken var current_token: ^ElnaLexerToken := nil first_char: Word8 @@ -401,11 +384,11 @@ begin source_code_advance(@source_code); lexer_identifier(@source_code, token_buffer); - current_token := malloc(#size(ElnaLexerStringToken)); + current_token := malloc#[ElnaLexerStringToken](#size(ElnaLexerStringToken)); current_token^.kind := ElnaLexerKind.trait; cast(current_token: ^ElnaLexerStringToken)^.value := string_dup(string_buffer_clear(token_buffer)) elsif isdigit(cast(first_char: Int)) <> 0 then - current_token := malloc(#size(ElnaLexerIntegerToken)); + current_token := malloc#[ElnaLexerIntegerToken](#size(ElnaLexerIntegerToken)); lexer_number(@source_code, @cast(current_token: ^ElnaLexerIntegerToken)^.value); if source_code_expect(@source_code, 'u') then @@ -418,37 +401,37 @@ begin source_code_advance(@source_code); if source_code_empty(@source_code) then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.left_paren elsif source_code_head(source_code) = '*' then source_code_advance(@source_code); if lexer_comment(@source_code, token_buffer) then - current_token := malloc(#size(ElnaLexerStringToken)); + current_token := malloc#[ElnaLexerStringToken](#size(ElnaLexerStringToken)); cast(current_token: ^ElnaLexerStringToken)^.value := string_dup(string_buffer_clear(token_buffer)); current_token^.kind := ElnaLexerKind.comment end else - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.left_paren end elsif first_char = ')' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.right_paren; source_code_advance(@source_code) elsif first_char = '{' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.left_brace; source_code_advance(@source_code) elsif first_char = '}' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.right_brace; source_code_advance(@source_code) elsif first_char = '\'' then source_code_advance(@source_code); if lexer_character(@source_code, @first_char) & source_code_expect(@source_code, '\'') then - current_token := malloc(#size(ElnaLexerCharacterToken)); + current_token := malloc#[ElnaLexerCharacterToken](#size(ElnaLexerCharacterToken)); current_token^.kind := ElnaLexerKind.character; cast(current_token: ^ElnaLexerCharacterToken)^.value := first_char; source_code_advance(@source_code) @@ -457,21 +440,21 @@ begin source_code_advance(@source_code); if lexer_string(@source_code, token_buffer) then - current_token := malloc(#size(ElnaLexerStringToken)); + current_token := malloc#[ElnaLexerStringToken](#size(ElnaLexerStringToken)); current_token^.kind := ElnaLexerKind.string; cast(current_token: ^ElnaLexerStringToken)^.value := string_dup(string_buffer_clear(token_buffer)) end elsif first_char = '[' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.left_square; source_code_advance(@source_code) elsif first_char = ']' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.right_square; source_code_advance(@source_code) elsif first_char = '>' then source_code_advance(@source_code); - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); if source_code_empty(@source_code) then current_token^.kind := ElnaLexerKind.greater_than @@ -486,7 +469,7 @@ begin end elsif first_char = '<' then source_code_advance(@source_code); - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); if source_code_empty(@source_code) then current_token^.kind := ElnaLexerKind.less_than @@ -503,28 +486,28 @@ begin current_token^.kind := ElnaLexerKind.less_than end elsif first_char = '=' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.equals; source_code_advance(@source_code) elsif first_char = ';' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.semicolon; source_code_advance(@source_code) elsif first_char = '.' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.dot; source_code_advance(@source_code) elsif first_char = ',' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.comma; source_code_advance(@source_code) elsif first_char = '+' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.plus; source_code_advance(@source_code) elsif first_char = '-' then source_code_advance(@source_code); - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); if source_code_empty(@source_code) then current_token^.kind := ElnaLexerKind.minus @@ -535,20 +518,20 @@ begin current_token^.kind := ElnaLexerKind.minus end elsif first_char = '*' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.multiplication; source_code_advance(@source_code) elsif first_char = '/' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.division; source_code_advance(@source_code) elsif first_char = '%' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.remainder; source_code_advance(@source_code) elsif first_char = ':' then source_code_advance(@source_code); - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); if source_code_empty(@source_code) then current_token^.kind := ElnaLexerKind.colon @@ -559,34 +542,34 @@ begin current_token^.kind := ElnaLexerKind.colon end elsif first_char = '^' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.hat; source_code_advance(@source_code) elsif first_char = '@' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.at; source_code_advance(@source_code) elsif first_char = '!' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.exclamation; source_code_advance(@source_code) elsif first_char = '&' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.and; source_code_advance(@source_code) elsif first_char = '~' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.not; source_code_advance(@source_code) elsif first_char = '|' then - current_token := malloc(#size(ElnaLexerToken)); + current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); current_token^.kind := ElnaLexerKind.pipe; source_code_advance(@source_code) end return current_token (* Split the source text into tokens. *) -proc lexer_text(source_code: SourceCode) -> Tokenizer +proc lexer_text#[T](source_code: SourceCode#[T]) -> Tokenizer var current_token: ^ElnaLexerToken token_buffer: StringBuffer @@ -769,7 +752,7 @@ return Compilation entry. *) -proc compile_in_stages(command_line: ^CommandLine; source_code: SourceCode) -> Int +proc compile_in_stages#[T](command_line: ^CommandLine; source_code: SourceCode#[T]) -> Int var return_code: Int := 0 lexer: Tokenizer @@ -786,7 +769,7 @@ proc process(argc: Int; argv: ^^Word8) -> Int var tokens: ^ElnaLexerToken tokens_size: Word - source_code: SourceCode + source_code: SourceCode#[SourceFile] command_line: ^CommandLine return_code: Int := 0 source_file: ^SourceFile @@ -821,7 +804,6 @@ begin return return_code proc initialize_global_state() -begin stdin := fdopen(0, "r\0".ptr); stdout := fdopen(1, "w\0".ptr); stderr := fdopen(2, "w\0".ptr) diff --git a/testsuite/compilable/generic_alias.elna b/testsuite/compilable/generic_alias.elna index 47ac638..da9501a 100644 --- a/testsuite/compilable/generic_alias.elna +++ b/testsuite/compilable/generic_alias.elna @@ -6,7 +6,7 @@ type Node#[T] = record next: ^Node#[T]; - value: T + value: ^T end Ref#[T] = ^T @@ -16,10 +16,10 @@ type end var - chain: Node#[^File] - aliased: Ref#[^File] - raw: ^^File - boxed: Boxed#[^File] + chain: Node#[File] + aliased: Ref#[File] + raw: ^File + boxed: Boxed#[File] begin chain.next := nil; diff --git a/testsuite/compilable/generic_arguments.elna b/testsuite/compilable/generic_arguments.elna index 4d33db5..1cda57f 100644 --- a/testsuite/compilable/generic_arguments.elna +++ b/testsuite/compilable/generic_arguments.elna @@ -5,22 +5,22 @@ type end Pair#[K, V] = record - key: K; - value: V + key: ^K; + value: ^V end var - entry: Pair#[^File, ^Word8] + entry: Pair#[File, Word8] -proc allocate#[T](size: Word) -> T +proc allocate#[T](size: Word) -> ^T extern -proc first#[K, V](entry_ptr: ^Pair#[K, V]) -> K +proc first#[K, V](entry_ptr: ^Pair#[K, V]) -> ^K return entry_ptr^.key begin - entry.key := allocate#[^File](#size(File)); - assert(#size(Pair#[^File, ^Word8]) = #size(Pointer) * 2u); - assert(#offset(Pair#[^File, ^Word8], value) = #size(Pointer)); - assert(first#[^File, ^Word8](@entry) = entry.key) + entry.key := allocate#[File](#size(File)); + assert(#size(Pair#[File, Word8]) = #size(Pointer) * 2u); + assert(#offset(Pair#[File, Word8], value) = #size(Pointer)); + assert(first#[File, Word8](@entry) = entry.key) end. diff --git a/testsuite/compilable/generic_base_chain.elna b/testsuite/compilable/generic_base_chain.elna index c303e6d..1abe199 100644 --- a/testsuite/compilable/generic_base_chain.elna +++ b/testsuite/compilable/generic_base_chain.elna @@ -5,20 +5,20 @@ type end Map#[K, V] = record - key: K; - value: V + key: ^K; + value: ^V end - Cache#[K, V] = record(Map#[^Word8, V]) - newest: K + Cache#[K, V] = record(Map#[Word8, V]) + newest: ^K end var - store: Cache#[^Int, ^File] + store: Cache#[Int, File] byte_key: ^Word8 - upcast: ^Map#[^Word8, ^File] + upcast: ^Map#[Word8, File] -proc put#[K2, V2](target: ^Map#[K2, V2]; key: K2) +proc put#[K2, V2](target: ^Map#[K2, V2]; key: ^K2) begin target^.key := key return diff --git a/testsuite/compilable/generic_const_inference.elna b/testsuite/compilable/generic_const_inference.elna index a9fc41f..7ce197f 100644 --- a/testsuite/compilable/generic_const_inference.elna +++ b/testsuite/compilable/generic_const_inference.elna @@ -10,10 +10,10 @@ var nested: NestedConst := nil direct_const: const ^Word8 := nil -proc write#[T](fd: Int; buf: T; count: Int) -> Int +proc write#[T](fd: Int; buf: ^T; count: Int) -> Int return 0 -proc write_const#[T](fd: Int; buf: const T; count: Int) -> Int +proc write_const#[T](fd: Int; buf: ^const T; count: Int) -> Int return 0 begin diff --git a/testsuite/compilable/generic_inference.elna b/testsuite/compilable/generic_inference.elna index 860eab1..9d7fed6 100644 --- a/testsuite/compilable/generic_inference.elna +++ b/testsuite/compilable/generic_inference.elna @@ -5,20 +5,20 @@ type end Cell#[T] = record - held: T + held: ^T end var - files: Cell#[^File] - bytes: Cell#[^Word8] + files: Cell#[File] + bytes: Cell#[Word8] f: File b: Word8 -proc store#[T](target: ^Cell#[T]; value: T) +proc store#[T](target: ^Cell#[T]; value: ^T) target^.held := value return -proc relay#[T](target: ^Cell#[T]; value: T) +proc relay#[T](target: ^Cell#[T]; value: ^T) store(target, value) return diff --git a/testsuite/compilable/generic_pointee.elna b/testsuite/compilable/generic_pointee.elna new file mode 100644 index 0000000..5ecaedf --- /dev/null +++ b/testsuite/compilable/generic_pointee.elna @@ -0,0 +1,17 @@ +program() + +type + File = record + fd: Int + end + +proc allocate#[T](size: Word) -> ^T +extern + +var + f: ^File + +begin + f := allocate#[File](#size(File)); + assert(f = nil) +end. diff --git a/testsuite/fail_compilation/generic_arity.elna b/testsuite/fail_compilation/generic_arity.elna index 645aded..3284a83 100644 --- a/testsuite/fail_compilation/generic_arity.elna +++ b/testsuite/fail_compilation/generic_arity.elna @@ -2,7 +2,7 @@ module type Stack#[T] = record - items: T + items: ^T end var diff --git a/testsuite/fail_compilation/generic_base_mismatch.elna b/testsuite/fail_compilation/generic_base_mismatch.elna index e361052..dd3bec7 100644 --- a/testsuite/fail_compilation/generic_base_mismatch.elna +++ b/testsuite/fail_compilation/generic_base_mismatch.elna @@ -8,17 +8,17 @@ type end List#[T] = record - head: T + head: ^T end Queue#[T] = record(List#[T]) - tail: T + tail: ^T end var - jobs: Queue#[^File] - wrong: ^List#[^Socket] + jobs: Queue#[File] + wrong: ^List#[Socket] begin - wrong := @jobs (* @Error Expected type '\^List#\[\^Socket\]', but got '\^Queue#\[\^File\]' *) + wrong := @jobs (* @Error Expected type '\^List#\[Socket\]', but got '\^Queue#\[File\]' *) end. diff --git a/testsuite/fail_compilation/generic_by_value.elna b/testsuite/fail_compilation/generic_by_value.elna new file mode 100644 index 0000000..778feca --- /dev/null +++ b/testsuite/fail_compilation/generic_by_value.elna @@ -0,0 +1,7 @@ +module + +proc foo#[T](x: T) (* @Error Opaque type 'T' cannot be used as a procedure parameter *) +begin +return + +end. diff --git a/testsuite/fail_compilation/generic_field_by_value.elna b/testsuite/fail_compilation/generic_field_by_value.elna new file mode 100644 index 0000000..66f9b46 --- /dev/null +++ b/testsuite/fail_compilation/generic_field_by_value.elna @@ -0,0 +1,8 @@ +module + +type + Cell#[T] = record + field: T (* @Error Opaque type 'T' cannot be used as a record field type *) + end + +end. diff --git a/testsuite/fail_compilation/generic_parameter_arithmetic.elna b/testsuite/fail_compilation/generic_parameter_arithmetic.elna index e05b1ee..9f6909d 100644 --- a/testsuite/fail_compilation/generic_parameter_arithmetic.elna +++ b/testsuite/fail_compilation/generic_parameter_arithmetic.elna @@ -1,9 +1,8 @@ module -proc walk#[T](value: T; step: ^T) +proc walk#[T](step: ^T) begin - step := step + 1; - value := value + 1 (* @Error Type parameter 'T' cannot be used in pointer arithmetic *) + step := step + 1 (* @Error Type parameter 'T' cannot be used in pointer arithmetic *) return end. diff --git a/testsuite/fail_compilation/generic_uninferrable.elna b/testsuite/fail_compilation/generic_uninferrable.elna index b3556d6..7eca7a9 100644 --- a/testsuite/fail_compilation/generic_uninferrable.elna +++ b/testsuite/fail_compilation/generic_uninferrable.elna @@ -2,7 +2,7 @@ program() var got: ^Word8 -proc allocate#[R](size: Word) -> R +proc allocate#[R](size: Word) -> ^R extern begin diff --git a/testsuite/runnable/generic_base.elna b/testsuite/runnable/generic_base.elna index 63737e0..161c59d 100644 --- a/testsuite/runnable/generic_base.elna +++ b/testsuite/runnable/generic_base.elna @@ -5,26 +5,26 @@ type end List#[T] = record - head: T; + head: ^T; count: Word end Queue#[T] = record(List#[T]) - tail: T + tail: ^T end var - jobs: Queue#[^File] - seen: ^List#[^File] + jobs: Queue#[File] + seen: ^List#[File] f: File -proc push#[T](target: ^List#[T]; value: T) +proc push#[T](target: ^List#[T]; value: ^T) begin target^.head := value; target^.count := target^.count + 1u return -proc enqueue#[T](target: ^Queue#[T]; value: T) +proc enqueue#[T](target: ^Queue#[T]; value: ^T) begin push(target, value); target^.tail := value @@ -36,5 +36,5 @@ begin assert(jobs.count = 1u); assert(jobs.head = @f); assert(jobs.tail = @f); - assert(#size(Queue#[^File]) = #size(Pointer) * 3u) + assert(#size(Queue#[File]) = #size(Pointer) * 3u) end. diff --git a/testsuite/runnable/generic_constructor.elna b/testsuite/runnable/generic_constructor.elna index d0a3f78..b21cd4a 100644 --- a/testsuite/runnable/generic_constructor.elna +++ b/testsuite/runnable/generic_constructor.elna @@ -5,16 +5,16 @@ type end Stack#[T] = record - items: T; + items: ^T; top: Word end var - s: Stack#[^File] + s: Stack#[File] f: File begin - s := Stack#[^File]{ top: 1u, items: @f }; + s := Stack#[File]{ top: 1u, items: @f }; assert(s.top = 1u); assert(s.items = @f) end. diff --git a/testsuite/runnable/generic_erasure.elna b/testsuite/runnable/generic_erasure.elna index 20862fa..db4d8c9 100644 --- a/testsuite/runnable/generic_erasure.elna +++ b/testsuite/runnable/generic_erasure.elna @@ -5,16 +5,16 @@ type end Cell#[T] = record - held: T + held: ^T end var - files: Cell#[^File] - bytes: Cell#[^Word8] + files: Cell#[File] + bytes: Cell#[Word8] f: File b: Word8 -proc store#[T](target: ^Cell#[T]; value: T) +proc store#[T](target: ^Cell#[T]; value: ^T) begin target^.held := value return @@ -22,8 +22,8 @@ return begin f.fd := 7; b := 3u8; - store#[^File](@files, @f); - store#[^Word8](@bytes, @b); + store#[File](@files, @f); + store#[Word8](@bytes, @b); assert(files.held^.fd = 7); assert(bytes.held^ = 3u8) end. diff --git a/testsuite/runnable/generic_record.elna b/testsuite/runnable/generic_record.elna index 4164c3d..1fff97d 100644 --- a/testsuite/runnable/generic_record.elna +++ b/testsuite/runnable/generic_record.elna @@ -5,15 +5,15 @@ type end Stack#[T] = record - items: T; + items: ^T; top: Word end var - s: Stack#[^File] + s: Stack#[File] f: File -proc push#[T](target: ^Stack#[T]; value: T) +proc push#[T](target: ^Stack#[T]; value: ^T) begin target^.items := value; target^.top := target^.top + 1u @@ -21,7 +21,7 @@ return begin s.top := 0u; - push#[^File](@s, @f); + push#[File](@s, @f); assert(s.top = 1u); assert(s.items = @f) end. |
