Make `extern` keyword redundant
c53210515bb30a51ea8f4b23803945305e1d72f9418e1b1bd80b529c222c733c
It's strictly not needed.
1 parent
e6e66a53
lib/std/lang/parser.rad
+16 -3
| 1920 | 1920 | return try parseMethodDecl(p, attrs); |
|
| 1921 | 1921 | } |
|
| 1922 | 1922 | let name = try parseIdent(p, "expected function name"); |
|
| 1923 | 1923 | let sig = try parseFnTypeSig(p); |
|
| 1924 | 1924 | let mut body: ?*ast::Node = nil; |
|
| 1925 | + | let mut fnAttrs = attrs; |
|
| 1925 | 1926 | ||
| 1926 | - | if let a = attrs; ast::attributesContains(&a, ast::Attribute::Extern) { |
|
| 1927 | - | try expect(p, scanner::TokenKind::Semicolon, "expected `;` after extern function declaration"); |
|
| 1927 | + | if consume(p, scanner::TokenKind::Semicolon) { |
|
| 1928 | + | if let a = attrs; ast::attributesContains(&a, ast::Attribute::Extern) { |
|
| 1929 | + | // Keep existing attributes unchanged. |
|
| 1930 | + | } else { |
|
| 1931 | + | let mut list = ast::nodeSlice(p.arena, 4); |
|
| 1932 | + | if let a = attrs { |
|
| 1933 | + | for i in 0..a.list.len { |
|
| 1934 | + | list.append(a.list[i], p.allocator); |
|
| 1935 | + | } |
|
| 1936 | + | } |
|
| 1937 | + | let attrNode = nodeAttribute(p, ast::Attribute::Extern); |
|
| 1938 | + | list.append(attrNode, p.allocator); |
|
| 1939 | + | fnAttrs = ast::Attributes { list }; |
|
| 1940 | + | } |
|
| 1928 | 1941 | } else { |
|
| 1929 | 1942 | body = try parseBlock(p); |
|
| 1930 | 1943 | } |
|
| 1931 | 1944 | return node(p, ast::NodeValue::FnDecl( |
|
| 1932 | - | ast::FnDecl { name, sig, body, attrs } |
|
| 1945 | + | ast::FnDecl { name, sig, body, attrs: fnAttrs } |
|
| 1933 | 1946 | )); |
|
| 1934 | 1947 | } |
|
| 1935 | 1948 | ||
| 1936 | 1949 | /// Parse a pointer or slice type. |
|
| 1937 | 1950 | fn parsePointerType(p: *mut Parser) -> *ast::Node |
lib/std/lang/parser/tests.rad
+57 -0
| 1139 | 1139 | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Pub)); |
|
| 1140 | 1140 | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Extern)); |
|
| 1141 | 1141 | try testing::expect(decl.body == nil); |
|
| 1142 | 1142 | } |
|
| 1143 | 1143 | ||
| 1144 | + | @test fn testParseFnDeclAttributesExplicitExternKeepsTwoAttrs() throws (testing::TestError) { |
|
| 1145 | + | let node = try! parseStmtStr("pub extern fn explicit();"); |
|
| 1146 | + | let case ast::NodeValue::FnDecl(decl) = node.value |
|
| 1147 | + | else throw testing::TestError::Failed; |
|
| 1148 | + | ||
| 1149 | + | let attrs = decl.attrs |
|
| 1150 | + | else throw testing::TestError::Failed; |
|
| 1151 | + | try testing::expect(attrs.list.len == 2); |
|
| 1152 | + | } |
|
| 1153 | + | ||
| 1154 | + | /// Test parsing a top-level function declaration with inferred extern. |
|
| 1155 | + | @test fn testParseFnDeclInferredExtern() throws (testing::TestError) { |
|
| 1156 | + | let node = try! parseStmtStr("fn run();"); |
|
| 1157 | + | let case ast::NodeValue::FnDecl(decl) = node.value |
|
| 1158 | + | else throw testing::TestError::Failed; |
|
| 1159 | + | ||
| 1160 | + | try expectIdent(decl.name, "run"); |
|
| 1161 | + | ||
| 1162 | + | let attrs = decl.attrs |
|
| 1163 | + | else throw testing::TestError::Failed; |
|
| 1164 | + | ||
| 1165 | + | try testing::expect(attrs.list.len == 1); |
|
| 1166 | + | ||
| 1167 | + | let case ast::NodeValue::Attribute(attr0) = attrs.list[0].value |
|
| 1168 | + | else throw testing::TestError::Failed; |
|
| 1169 | + | try testing::expect(attr0 == ast::Attribute::Extern); |
|
| 1170 | + | ||
| 1171 | + | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Extern)); |
|
| 1172 | + | try testing::expect(decl.body == nil); |
|
| 1173 | + | } |
|
| 1174 | + | ||
| 1175 | + | /// Test parsing a top-level exported function declaration with inferred extern. |
|
| 1176 | + | @test fn testParseFnDeclExportInferredExtern() throws (testing::TestError) { |
|
| 1177 | + | let node = try! parseStmtStr("export fn run();"); |
|
| 1178 | + | let case ast::NodeValue::FnDecl(decl) = node.value |
|
| 1179 | + | else throw testing::TestError::Failed; |
|
| 1180 | + | ||
| 1181 | + | try expectIdent(decl.name, "run"); |
|
| 1182 | + | ||
| 1183 | + | let attrs = decl.attrs |
|
| 1184 | + | else throw testing::TestError::Failed; |
|
| 1185 | + | ||
| 1186 | + | try testing::expect(attrs.list.len == 2); |
|
| 1187 | + | ||
| 1188 | + | let case ast::NodeValue::Attribute(attr0) = attrs.list[0].value |
|
| 1189 | + | else throw testing::TestError::Failed; |
|
| 1190 | + | try testing::expect(attr0 == ast::Attribute::Pub); |
|
| 1191 | + | ||
| 1192 | + | let case ast::NodeValue::Attribute(attr1) = attrs.list[1].value |
|
| 1193 | + | else throw testing::TestError::Failed; |
|
| 1194 | + | try testing::expect(attr1 == ast::Attribute::Extern); |
|
| 1195 | + | ||
| 1196 | + | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Pub)); |
|
| 1197 | + | try testing::expect(ast::attributesContains(&attrs, ast::Attribute::Extern)); |
|
| 1198 | + | try testing::expect(decl.body == nil); |
|
| 1199 | + | } |
|
| 1200 | + | ||
| 1144 | 1201 | /// Test parsing a scoped identifier type. |
|
| 1145 | 1202 | @test fn testParseTypeScopedIdent() throws (testing::TestError) { |
|
| 1146 | 1203 | let node = try! parseTypeStr("module::Type"); |
|
| 1147 | 1204 | let case ast::NodeValue::TypeSig(ts) = node.value |
|
| 1148 | 1205 | else throw testing::TestError::Failed; |
test/tests/extern.inferred.rad
added
+5 -0
| 1 | + | fn externalFoo() -> i32; |
|
| 2 | + | ||
| 3 | + | @default fn main() -> i32 { |
|
| 4 | + | return 0; |
|
| 5 | + | } |