@@ -259,6 +259,7 @@ struct FastcStructField {
259259 name string
260260 typ string
261261 is_public bool
262+ is_required bool
262263 module_name string
263264 path string
264265 imports map [string ]string
@@ -689,6 +690,56 @@ fn fastc_resolve_source_files(paths []string, prefs &pref.Preferences) ![]FastcS
689690 return sources
690691}
691692
693+ fn fastc_sources_in_dependency_order (sources []FastcSourceFile) ! []FastcSourceFile {
694+ mut module_order := []string {}
695+ for source_file in sources {
696+ module_name := source_file.header.module_name
697+ if module_name ! in module_order {
698+ module_order << module_name
699+ }
700+ }
701+ mut visiting := []string {}
702+ mut visited := []string {}
703+ mut ordered := []FastcSourceFile{cap: sources.len}
704+ for module_name in module_order {
705+ fastc_append_module_sources (module_name, sources, mut visiting, mut visited, mut ordered)!
706+ }
707+ return ordered
708+ }
709+
710+ fn fastc_append_module_sources (module_name string , sources []FastcSourceFile, mut visiting []string , mut visited []string , mut ordered []FastcSourceFile) ! {
711+ if module_name in visited {
712+ return
713+ }
714+ if module_name in visiting {
715+ return error ('fastc parser does not support cyclic module dependency involving `${module_name }`' )
716+ }
717+ visiting << module_name
718+ mut dependencies := []string {}
719+ for source_file in sources {
720+ if source_file.header.module_name != module_name {
721+ continue
722+ }
723+ imports := source_file.header.imports.clone ()
724+ for dependency in imports.values () {
725+ if dependency != module_name && dependency ! in dependencies {
726+ dependencies << dependency
727+ }
728+ }
729+ }
730+ dependencies.sort ()
731+ for dependency in dependencies {
732+ fastc_append_module_sources (dependency, sources, mut visiting, mut visited, mut ordered)!
733+ }
734+ for source_file in sources {
735+ if source_file.header.module_name == module_name {
736+ ordered << source_file
737+ }
738+ }
739+ visiting.delete (visiting.len - 1 )
740+ visited << module_name
741+ }
742+
692743fn fastc_source_file_matches_backend (path string ) bool {
693744 return ! path.ends_with ('.arm64.v' ) && ! path.ends_with ('.amd64.v' )
694745 && ! path.ends_with ('.native.v' ) && ! path.ends_with ('.wasm.v' ) && ! path.ends_with ('.rv64.v' )
@@ -1004,7 +1055,8 @@ fn collect_global_names(source string, path string, module_name string, prefs &p
10041055fn fastc_generate_global_declarations (sources []FastcSourceFile, prefs & pref.Preferences, declared_types map [string ]bool , declared_kinds map [string ]FastcDeclaredTypeKind, struct_fields map [string ]map [string ]string , struct_field_info map [string ][]FastcStructField, functions map [string ]FastcFunctionSignature, constants map [string ]string , public_constants map [string ]bool , constant_types map [string ]string , globals map [string ]string , mut global_types map [string ]string ) ! FastcGlobalDeclarations {
10051056 mut out := strings.new_builder (1024 )
10061057 mut initializers := strings.new_builder (1024 )
1007- for source_file in sources {
1058+ ordered_sources := fastc_sources_in_dependency_order (sources)!
1059+ for source_file in ordered_sources {
10081060 mut file_set := token.FileSet.new ()
10091061 mut file := file_set.add_file (source_file.path, source_file.source.len)
10101062 file.index_lines (source_file.source)
@@ -1543,6 +1595,12 @@ fn fastc_emit_struct_declaration(mut scan scanner.Scanner, is_union bool, source
15431595 }
15441596 tok = next_token
15451597 fastc_register_composite_type (field_type, mut composite_types)
1598+ mut is_required := false
1599+ for tok == .attribute {
1600+ mut attribute_is_required := false
1601+ tok , attribute_is_required = fastc_scan_struct_field_attribute (mut scan)!
1602+ is_required = is_required || attribute_is_required
1603+ }
15461604 mut default_source := ''
15471605 if tok == .assign {
15481606 first_default_token := scan.scan ()
@@ -1569,6 +1627,7 @@ fn fastc_emit_struct_declaration(mut scan scanner.Scanner, is_union bool, source
15691627 name: field_name
15701628 typ: field_type
15711629 is_public: fields_are_public
1630+ is_required: is_required
15721631 module_name: source_file.header.module_name
15731632 path: source_file.path
15741633 imports: source_file.header.imports.clone ()
@@ -1662,8 +1721,16 @@ fn fastc_emit_enum_declaration(mut scan scanner.Scanner, source_file FastcSource
16621721 tok = scan.scan ()
16631722 if tok == .assign {
16641723 tok = scan.scan ()
1724+ mut sign := 1
1725+ if tok in [.plus, .minus] {
1726+ sign = if tok == .minus { - 1 } else { 1 }
1727+ tok = scan.scan ()
1728+ }
16651729 if tok == .number {
16661730 value = scan.lit.int ()
1731+ if sign < 0 {
1732+ value = - value
1733+ }
16671734 tok = scan.scan ()
16681735 } else {
16691736 tok = fastc_skip_field_default_from_token (mut scan, tok)!
@@ -1832,6 +1899,27 @@ fn fastc_skip_attribute(mut scan scanner.Scanner) !token.Token {
18321899 return tok
18331900}
18341901
1902+ fn fastc_scan_struct_field_attribute (mut scan scanner.Scanner) ! (token.Token, bool ) {
1903+ mut tok := scan.scan ()
1904+ mut depth := 1
1905+ mut is_required := false
1906+ for depth > 0 {
1907+ if tok == .eof {
1908+ return error ('fastc parser does not support unfinished struct field attribute' )
1909+ }
1910+ if tok == .name && scan.lit == 'required' {
1911+ is_required = true
1912+ }
1913+ if tok == .lsbr {
1914+ depth++
1915+ } else if tok == .rsbr {
1916+ depth--
1917+ }
1918+ tok = scan.scan ()
1919+ }
1920+ return tok, is_required
1921+ }
1922+
18351923fn fastc_skip_balanced_tokens (mut scan scanner.Scanner, first token.Token, open token.Token, close token.Token) ! token.Token {
18361924 mut tok := first
18371925 mut depth := 0
@@ -4108,6 +4196,9 @@ fn (mut g Parser) parse_for() !bool {
41084196 || ! fastc_is_integer_expression_type (end_expression_type) {
41094197 return g.unsupported ('range bounds of types `${start_expression_type }` and `${end_expression_type }` must both be integers' )
41104198 }
4199+ if ! fastc_range_types_are_compatible (start_expression_type, end_expression_type) {
4200+ return g.unsupported ('range bounds of types `${start_expression_type }` and `${end_expression_type }` must have compatible integer types' )
4201+ }
41114202 if start_value := fastc_integer_literal_value (start_expression) {
41124203 if end_value := fastc_integer_literal_value (end_expression) {
41134204 if start_value > = end_value {
@@ -9742,6 +9833,8 @@ fn (g &Parser) validate_struct_literal_field_visibility(tokens []FastcExpression
97429833 }
97439834 close := fastc_matching_delimiter (tokens, open, .lcbr, .rcbr) or { return }
97449835 mut index := open + 1
9836+ mut initialized_fields := map [string ]bool {}
9837+ mut has_update := false
97459838 for index < close {
97469839 for index < close && tokens[index].tok in [.semicolon, .comma] {
97479840 index++
@@ -9750,6 +9843,7 @@ fn (g &Parser) validate_struct_literal_field_visibility(tokens []FastcExpression
97509843 break
97519844 }
97529845 if tokens[index].tok == .ellipsis {
9846+ has_update = true
97539847 index++
97549848 for index < close && tokens[index].tok ! in [.semicolon, .comma] {
97559849 index++
@@ -9761,6 +9855,7 @@ fn (g &Parser) validate_struct_literal_field_visibility(tokens []FastcExpression
97619855 }
97629856 field_name := tokens[index].lit
97639857 field := g.struct_field_metadata (c_type, field_name) or { return }
9858+ initialized_fields[field_name] = true
97649859 if ! g.struct_field_is_visible (field) {
97659860 type_name := g.semantic_type_key (c_type).all_after_last ('.' )
97669861 return g.unsupported ('private field `${type_name }.${field .name }` from imported module `${field .module_name }`' )
@@ -9802,6 +9897,14 @@ fn (g &Parser) validate_struct_literal_field_visibility(tokens []FastcExpression
98029897 index++
98039898 }
98049899 }
9900+ if ! has_update {
9901+ for field in g.struct_field_info[layout_type] {
9902+ if field.is_required && field.name ! in initialized_fields {
9903+ type_name := g.semantic_type_key (c_type).all_after_last ('.' )
9904+ return g.unsupported ('field `${type_name }.${field .name }` must be initialized' )
9905+ }
9906+ }
9907+ }
98059908}
98069909
98079910fn fastc_matching_rpar (tokens []FastcExpressionToken, open int ) ? int {
@@ -10424,11 +10527,40 @@ fn fastc_number_expression_type(literal string) string {
1042410527}
1042510528
1042610529fn fastc_integer_literal_value (tokens []FastcExpressionToken) ? i64 {
10427- if tokens.len != 1 || tokens[0 ].tok != .number
10428- || fastc_number_expression_type (tokens[0 ].lit) != 'integer literal' {
10530+ mut sign := i64 (1 )
10531+ mut number_index := 0
10532+ if tokens.len == 2 && tokens[0 ].tok in [.plus, .minus] {
10533+ sign = if tokens[0 ].tok == .minus { - 1 } else { 1 }
10534+ number_index = 1
10535+ } else if tokens.len != 1 {
1042910536 return none
1043010537 }
10431- return tokens[0 ].lit.replace ('_' , '' ).i64 ()
10538+ if tokens[number_index].tok != .number
10539+ || fastc_number_expression_type (tokens[number_index].lit) != 'integer literal' {
10540+ return none
10541+ }
10542+ mut value := tokens[number_index].lit.replace ('_' , '' ).i64 ()
10543+ if sign < 0 {
10544+ value = - value
10545+ }
10546+ return value
10547+ }
10548+
10549+ fn fastc_range_types_are_compatible (left string , right string ) bool {
10550+ if left == right {
10551+ return true
10552+ }
10553+ if fastc_is_integer_literal_expression_type (left)
10554+ && fastc_is_integer_literal_expression_type (right) {
10555+ return true
10556+ }
10557+ if fastc_is_integer_literal_expression_type (left) {
10558+ return fastc_call_types_are_compatible (left, right)
10559+ }
10560+ if fastc_is_integer_literal_expression_type (right) {
10561+ return fastc_call_types_are_compatible (right, left)
10562+ }
10563+ return false
1043210564}
1043310565
1043410566fn fastc_common_arithmetic_type (left string , right string ) string {
0 commit comments