aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/ast.cc5
-rw-r--r--boot/dependency.cc2
-rw-r--r--boot/parser.yy20
-rw-r--r--boot/symbol.cc17
-rw-r--r--include/elna/boot/ast.h8
-rw-r--r--include/elna/boot/dependency.h5
-rw-r--r--include/elna/boot/symbol.h9
-rw-r--r--rakelib/gcc.rake5
-rw-r--r--source/command_line_interface.elna2
-rw-r--r--source/common.elna3
-rw-r--r--source/diagnostic.elna2
-rw-r--r--source/lexer.elna6
-rw-r--r--source/main.elna2
-rw-r--r--source/name_analysis.elna2
-rw-r--r--source/parser.elna4
-rw-r--r--source/qbe.elna2
-rw-r--r--source/symbol.elna2
-rw-r--r--source/sys/posix/cctype.elna (renamed from source/cctype.elna)0
-rw-r--r--source/sys/posix/cstdio.elna (renamed from source/cstdio.elna)0
-rw-r--r--source/sys/posix/cstdlib.elna (renamed from source/cstdlib.elna)0
-rw-r--r--source/sys/posix/cstring.elna (renamed from source/cstring.elna)0
-rw-r--r--source/tac.elna2
-rw-r--r--testsuite/fail_compilation/transitive_import/helper.elna6
-rw-r--r--testsuite/fail_compilation/transitive_import/middle.elna5
-rw-r--r--testsuite/fail_compilation/transitive_import/sut.elna8
-rw-r--r--testsuite/runnable/reexport/helper.elna6
-rw-r--r--testsuite/runnable/reexport/left.elna5
-rw-r--r--testsuite/runnable/reexport/middle.elna5
-rw-r--r--testsuite/runnable/reexport/right.elna5
-rw-r--r--testsuite/runnable/reexport/sut.elna6
-rw-r--r--tools/tree-sitter/grammar.js9
31 files changed, 119 insertions, 34 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index 69b15d3..456797a 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -1681,8 +1681,9 @@ namespace elna::boot
delete this->alternative;
}
- import_declaration::import_declaration(const source_position position, std::vector<std::string>&& segments)
- : node(position), segments(std::move(segments))
+ import_declaration::import_declaration(const source_position position, std::vector<std::string>&& segments,
+ const bool exported)
+ : node(position), segments(std::move(segments)), exported(exported)
{
}
diff --git a/boot/dependency.cc b/boot/dependency.cc
index 5053a36..31eccc9 100644
--- a/boot/dependency.cc
+++ b/boot/dependency.cc
@@ -90,7 +90,7 @@ namespace elna::boot
}
for (const auto& import : imports)
{
- const std::vector<import_collision> collisions = result.value.add_import(import.symbols);
+ const std::vector<import_collision> collisions = result.value.add_import(import.symbols, import.reexport);
for (const import_collision& collision : collisions)
{
diff --git a/boot/parser.yy b/boot/parser.yy
index cfa63d5..65d3dba 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -160,7 +160,8 @@ along with GCC; see the file COPYING3. If not see
%type <std::vector<elna::boot::identifier_definition>> identifier_definitions;
%type <std::unique_ptr<elna::boot::attribute>> attribute;
%type <std::vector<elna::boot::attribute>> attributes;
-%type <std::vector<std::string>> import_declaration;
+%type <std::pair<std::vector<std::string>, bool>> import_declaration;
+%type <std::vector<std::string>> import_path;
%type <std::vector<elna::boot::identifier>> required_identifiers optional_identifiers generic_parameters;
%type <std::unique_ptr<elna::boot::enumeration_type_expression::member_declaration>> enumeration_member;
%type <std::vector<elna::boot::enumeration_type_expression::member_declaration>> enumeration_members;
@@ -736,22 +737,31 @@ variable_declarations:
$$ = $2;
$$.insert(std::cbegin($$), $1);
}
-import_declaration:
- IDENTIFIER "." import_declaration
+import_path:
+ IDENTIFIER "." import_path
{
$$ = $3;
$$.emplace($$.cbegin(), $1);
}
| IDENTIFIER { $$.emplace_back($1); }
+import_declaration:
+ import_path "*" { $$ = { $1, true }; }
+ | import_path { $$ = { $1, false }; }
import_declarations:
import_declaration "," import_declarations
{
+ auto [segments, exported] = $1;
+
$$ = $3;
- $$.emplace($$.cbegin(), new boot::import_declaration(boot::make_position(@$), $1));
+ $$.emplace($$.cbegin(),
+ new boot::import_declaration(boot::make_position(@$), std::move(segments), exported));
}
| import_declaration
{
- $$.emplace_back(new boot::import_declaration(boot::make_position(@$), $1));
+ auto [segments, exported] = $1;
+
+ $$.emplace_back(
+ new boot::import_declaration(boot::make_position(@$), std::move(segments), exported));
}
type_declaration:
identifier_definition generic_parameters "=" type_expression
diff --git a/boot/symbol.cc b/boot/symbol.cc
index 375cbfd..2805839 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -522,7 +522,8 @@ namespace elna::boot
return this->unresolved.insert({ symbol_name, std::move(forward_declaration) }).second;
}
- std::vector<import_collision> symbol_bag::add_import(const std::shared_ptr<symbol_table>& symbols)
+ std::vector<import_collision> symbol_bag::add_import(const std::shared_ptr<symbol_table>& symbols,
+ const bool reexport)
{
std::vector<import_collision> collisions;
@@ -538,7 +539,10 @@ namespace elna::boot
}
}
this->imports.push_back(symbols);
-
+ if (reexport)
+ {
+ this->reexports.push_back(symbols);
+ }
return collisions;
}
@@ -553,6 +557,15 @@ namespace elna::boot
if (!m_exported)
{
m_exported = std::make_shared<symbol_table>(symbols->scope());
+ // The same symbol can reach a module along several re-export
+ // paths; it is the same info then, so entering it twice is a no-op.
+ for (const auto& reexported : this->reexports)
+ {
+ for (const auto& [name, info] : *reexported)
+ {
+ m_exported->enter(name, info);
+ }
+ }
for (const auto& [name, info] : *symbols)
{
if (info->exported)
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index 6edeb25..06e5d41 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -1027,13 +1027,19 @@ namespace elna::boot
/**
* Import statement.
+ *
+ * An asterisk after the module path marks a re-export: the symbols the
+ * imported module exports become visible to the modules importing this
+ * one as well.
*/
class import_declaration : public node
{
public:
const std::vector<std::string> segments;
+ const bool exported;
- import_declaration(const source_position position, std::vector<std::string>&& segments);
+ import_declaration(const source_position position, std::vector<std::string>&& segments,
+ const bool exported = false);
void accept(parser_visitor *visitor) override;
};
diff --git a/include/elna/boot/dependency.h b/include/elna/boot/dependency.h
index 7bd3de9..f52bfb1 100644
--- a/include/elna/boot/dependency.h
+++ b/include/elna/boot/dependency.h
@@ -156,6 +156,8 @@ namespace elna::boot
{
source_position position;
std::shared_ptr<symbol_table> symbols;
+ /// Whether the importing module re-exports the symbols.
+ bool reexport = false;
};
/**
@@ -302,7 +304,8 @@ namespace elna::boot
}
imports.push_back({
.position = sub_tree->position(),
- .symbols = this->cache.find(module_path)->second.exported_symbols()
+ .symbols = this->cache.find(module_path)->second.exported_symbols(),
+ .reexport = sub_tree->exported
});
}
result.append(key, std::move(circular));
diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h
index 07bcf80..bdac269 100644
--- a/include/elna/boot/symbol.h
+++ b/include/elna/boot/symbol.h
@@ -558,6 +558,8 @@ namespace elna::boot
{
std::shared_ptr<symbol_table> symbols;
std::vector<std::shared_ptr<symbol_table>> imports;
+ // The subset of imports that is re-exported by this module.
+ std::vector<std::shared_ptr<symbol_table>> reexports;
forward_table unresolved;
std::shared_ptr<info> lookup_import(const std::string& name) const;
@@ -643,11 +645,14 @@ namespace elna::boot
* earlier import keeps its names.
*
* \param symbols Exported symbol table of another module.
+ * \param reexport Whether the imported symbols are exported by this
+ * module as well, so they are visible to its importers.
*
* \return Names an earlier import already brought into the scope,
* sorted by name.
*/
- std::vector<import_collision> add_import(const std::shared_ptr<symbol_table>& symbols);
+ std::vector<import_collision> add_import(const std::shared_ptr<symbol_table>& symbols,
+ const bool reexport = false);
/**
* Tells whether the current scope is the module global scope.
@@ -661,7 +666,7 @@ namespace elna::boot
/**
* The symbol table containing the exported declarations of the
- * module, computed lazily. Must be called while the current scope is
+ * module and the symbols of the modules it re-exports, computed lazily. Must be called while the current scope is
* still the module scope.
*
* \return Exported symbols of the module.
diff --git a/rakelib/gcc.rake b/rakelib/gcc.rake
index 6dce877..aeffd06 100644
--- a/rakelib/gcc.rake
+++ b/rakelib/gcc.rake
@@ -130,8 +130,9 @@ end
def multi_module_extra_sources(test_target)
sources = test_target.glob('**/*.elna')
- .map { |extra| %("#{extra.relative_path_from(test_target)}") }
- "(* { dg-additional-sources #{sources * ' '} } *)"
+ .map { |extra| extra.relative_path_from(test_target) }
+ .sort
+ "(* { dg-additional-sources \"#{sources * ' '}\" } *)"
end
def convert_multi_module_test(test_path, test_target, category)
diff --git a/source/command_line_interface.elna b/source/command_line_interface.elna
index 1318e67..4c3c1a6 100644
--- a/source/command_line_interface.elna
+++ b/source/command_line_interface.elna
@@ -5,7 +5,7 @@
Command line handling.
*)
module
-import cstdlib, cstring, common
+import sys.posix.cstdlib, sys.posix.cstring, common
type
CommandLine* = record
diff --git a/source/common.elna b/source/common.elna
index 65b0a65..93b4363 100644
--- a/source/common.elna
+++ b/source/common.elna
@@ -2,7 +2,7 @@
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
module
-import cstring, cstdio, cstdlib
+import sys.posix.cstring, sys.posix.cstdio, sys.posix.cstdlib
type
ElnaLocation* = record
@@ -86,4 +86,3 @@ begin
return nil
end.
-
diff --git a/source/diagnostic.elna b/source/diagnostic.elna
index 771ce38..2356544 100644
--- a/source/diagnostic.elna
+++ b/source/diagnostic.elna
@@ -2,7 +2,7 @@
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
module
-import common, cstdio, cstdlib, lexer, ast
+import common, sys.posix.cstdio, sys.posix.cstdlib, lexer, ast
type
ElnaErrorKind* = (
diff --git a/source/lexer.elna b/source/lexer.elna
index 9ba593f..71e76a7 100644
--- a/source/lexer.elna
+++ b/source/lexer.elna
@@ -2,7 +2,7 @@
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
module
-import cstdio, common, cstdlib
+import sys.posix.cstdio, common, sys.posix.cstdlib
type
ElnaLexerState* = (
@@ -762,8 +762,8 @@ begin
cursor^.start := code_pointer;
cursor^.finish := code_pointer;
cursor^.token := nil;
- cursor^.position.start_location := ElnaLocation{ line: 1u, column: 1u };
- cursor^.position.end_location := ElnaLocation{ line: 1u, column: 1u }
+ cursor^.position.start_location := { ElnaLocation; line: 1u, column: 1u };
+ cursor^.position.end_location := { ElnaLocation; line: 1u, column: 1u }
return
(**
diff --git a/source/main.elna b/source/main.elna
index 6049362..3b78651 100644
--- a/source/main.elna
+++ b/source/main.elna
@@ -4,7 +4,7 @@
program(parameters)
import
- cstdio, cstdlib, cstring, common, command_line_interface,
+ sys.posix.cstdio, sys.posix.cstdlib, sys.posix.cstring, common, command_line_interface,
lexer, ast, diagnostic, symbol, parser, name_analysis, type_check, tac, qbe
proc read_file_to_buffer(filename: ^Word8) -> []const Word8
diff --git a/source/name_analysis.elna b/source/name_analysis.elna
index 75d6dbd..cbb27c0 100644
--- a/source/name_analysis.elna
+++ b/source/name_analysis.elna
@@ -2,7 +2,7 @@
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
module
-import common, cstdlib, lexer, ast, symbol, diagnostic
+import common, sys.posix.cstdlib, lexer, ast, symbol, diagnostic
proc elna_name_type_expression*(parser_node: ^ElnaTreeTypeExpression; error_list: ^ElnaList) -> ^ElnaType
var
diff --git a/source/parser.elna b/source/parser.elna
index 30f79f8..3912b65 100644
--- a/source/parser.elna
+++ b/source/parser.elna
@@ -2,7 +2,7 @@
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
module
-import common, cstdlib, lexer, ast, diagnostic
+import common, sys.posix.cstdlib, lexer, ast, diagnostic
proc elna_parser_expect*(cursor: ^ElnaLexerCursor; expected: ElnaLexerKind; error_list: ^ElnaList) -> ^ElnaLexerToken
var
@@ -1129,7 +1129,7 @@ var
begin
result := malloc#[ElnaTreeModuleDeclaration](#size(ElnaTreeModuleDeclaration));
result^.kind := ElnaTreeKind.module_declaration;
- result^.position.start_location := ElnaLocation{ line: 1u, column: 1u };
+ result^.position.start_location := { ElnaLocation; line: 1u, column: 1u };
result^.position.end_location := result^.position.start_location;
result^.types := elna_parser_type_part(cursor, error_list);
diff --git a/source/qbe.elna b/source/qbe.elna
index 0a5a45b..47eac88 100644
--- a/source/qbe.elna
+++ b/source/qbe.elna
@@ -2,7 +2,7 @@
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
module
-import common, cstdlib, cstdio, cstring, lexer, ast, symbol, tac
+import common, sys.posix.cstdlib, sys.posix.cstdio, sys.posix.cstring, lexer, ast, symbol, tac
var
qbe_unique_id: Word := 0u
diff --git a/source/symbol.elna b/source/symbol.elna
index 531f58c..a07a9f3 100644
--- a/source/symbol.elna
+++ b/source/symbol.elna
@@ -2,7 +2,7 @@
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
module
-import cstdlib, common, ast
+import sys.posix.cstdlib, common, ast
type
ElnaSymbolInfoKind* = (type_info, temporary_info, procedure_info)
diff --git a/source/cctype.elna b/source/sys/posix/cctype.elna
index 19c3491..19c3491 100644
--- a/source/cctype.elna
+++ b/source/sys/posix/cctype.elna
diff --git a/source/cstdio.elna b/source/sys/posix/cstdio.elna
index 928c7e1..928c7e1 100644
--- a/source/cstdio.elna
+++ b/source/sys/posix/cstdio.elna
diff --git a/source/cstdlib.elna b/source/sys/posix/cstdlib.elna
index 10a4d80..10a4d80 100644
--- a/source/cstdlib.elna
+++ b/source/sys/posix/cstdlib.elna
diff --git a/source/cstring.elna b/source/sys/posix/cstring.elna
index 3973573..3973573 100644
--- a/source/cstring.elna
+++ b/source/sys/posix/cstring.elna
diff --git a/source/tac.elna b/source/tac.elna
index 7b05ab2..3d65e42 100644
--- a/source/tac.elna
+++ b/source/tac.elna
@@ -2,7 +2,7 @@
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
module
-import common, cstdlib, cstdio, cstring, lexer, ast, symbol, diagnostic
+import common, sys.posix.cstdlib, sys.posix.cstdio, sys.posix.cstring, lexer, ast, symbol, diagnostic
type
ElnaTacOperator* = (
diff --git a/testsuite/fail_compilation/transitive_import/helper.elna b/testsuite/fail_compilation/transitive_import/helper.elna
new file mode 100644
index 0000000..c3c0bfd
--- /dev/null
+++ b/testsuite/fail_compilation/transitive_import/helper.elna
@@ -0,0 +1,6 @@
+module
+
+proc multiply*(x, y: Int) -> Int
+return x * y
+
+end.
diff --git a/testsuite/fail_compilation/transitive_import/middle.elna b/testsuite/fail_compilation/transitive_import/middle.elna
new file mode 100644
index 0000000..0aab392
--- /dev/null
+++ b/testsuite/fail_compilation/transitive_import/middle.elna
@@ -0,0 +1,5 @@
+module
+
+import helper
+
+end.
diff --git a/testsuite/fail_compilation/transitive_import/sut.elna b/testsuite/fail_compilation/transitive_import/sut.elna
new file mode 100644
index 0000000..5423dbd
--- /dev/null
+++ b/testsuite/fail_compilation/transitive_import/sut.elna
@@ -0,0 +1,8 @@
+module
+
+import middle
+
+proc call() -> Int
+return multiply(3, 4) (* @Error Symbol 'multiply' not declared *)
+
+end.
diff --git a/testsuite/runnable/reexport/helper.elna b/testsuite/runnable/reexport/helper.elna
new file mode 100644
index 0000000..c3c0bfd
--- /dev/null
+++ b/testsuite/runnable/reexport/helper.elna
@@ -0,0 +1,6 @@
+module
+
+proc multiply*(x, y: Int) -> Int
+return x * y
+
+end.
diff --git a/testsuite/runnable/reexport/left.elna b/testsuite/runnable/reexport/left.elna
new file mode 100644
index 0000000..f149065
--- /dev/null
+++ b/testsuite/runnable/reexport/left.elna
@@ -0,0 +1,5 @@
+module
+
+import helper*
+
+end.
diff --git a/testsuite/runnable/reexport/middle.elna b/testsuite/runnable/reexport/middle.elna
new file mode 100644
index 0000000..0e593db
--- /dev/null
+++ b/testsuite/runnable/reexport/middle.elna
@@ -0,0 +1,5 @@
+module
+
+import left*, right*
+
+end.
diff --git a/testsuite/runnable/reexport/right.elna b/testsuite/runnable/reexport/right.elna
new file mode 100644
index 0000000..f149065
--- /dev/null
+++ b/testsuite/runnable/reexport/right.elna
@@ -0,0 +1,5 @@
+module
+
+import helper*
+
+end.
diff --git a/testsuite/runnable/reexport/sut.elna b/testsuite/runnable/reexport/sut.elna
new file mode 100644
index 0000000..8ddb567
--- /dev/null
+++ b/testsuite/runnable/reexport/sut.elna
@@ -0,0 +1,6 @@
+program()
+import middle
+
+begin
+ assert(multiply(3, 4) = 12)
+end.
diff --git a/tools/tree-sitter/grammar.js b/tools/tree-sitter/grammar.js
index bfb4c26..b854e82 100644
--- a/tools/tree-sitter/grammar.js
+++ b/tools/tree-sitter/grammar.js
@@ -92,6 +92,7 @@ module.exports = grammar({
import_path: $ => seq(
$.identifier,
repeat(seq('.', $.identifier)),
+ optional(field('exported', '*')),
),
type_section: $ => seq(
@@ -485,12 +486,12 @@ module.exports = grammar({
')',
),
- record_constructor: $ => prec(PREC.CALL, seq(
- field('type', choice($.identifier, $.generic_type)),
+ record_constructor: $ => seq(
'{',
- optional(commaSep1($.field_initializer)),
+ field('type', $._type_expression),
+ optional(seq(';', commaSep1($.field_initializer))),
'}',
- )),
+ ),
field_initializer: $ => seq(
field('name', $.identifier),