@@ -290,6 +290,7 @@ struct Parser {
290290 declared_kinds map [string ]FastcDeclaredTypeKind
291291 struct_fields map [string ]map [string ]string
292292 constants map [string ]string
293+ public_constants map [string ]bool
293294 globals map [string ]string
294295 used_function_names map [string ]bool
295296 selfhost bool
@@ -356,14 +357,15 @@ fn generate_source_files(sources []FastcSourceFile, prefs &pref.Preferences) !st
356357 mut declared_kinds := map [string ]FastcDeclaredTypeKind{}
357358 mut struct_fields := map [string ]map [string ]string {}
358359 mut constants := map [string ]string {}
360+ mut public_constants := map [string ]bool {}
359361 mut globals := map [string ]string {}
360362 for source_file in sources {
361363 collect_declared_types (source_file.source, source_file.path,
362364 source_file.header.module_name, prefs, mut declared_types, mut declared_kinds)!
363365 }
364366 for source_file in sources {
365367 collect_constant_names (source_file.source, source_file.path,
366- source_file.header.module_name, prefs, mut constants)!
368+ source_file.header.module_name, prefs, mut constants, mut public_constants )!
367369 collect_global_names (source_file.source, source_file.path, source_file.header.module_name,
368370 prefs, mut globals)!
369371 }
@@ -392,11 +394,11 @@ fn generate_source_files(sources []FastcSourceFile, prefs &pref.Preferences) !st
392394 declared_kinds, mut struct_fields, mut composite_types)!
393395 mut constant_types := map [string ]string {}
394396 constant_declarations := fastc_generate_constant_declarations (sources, prefs, declared_types,
395- declared_kinds, struct_fields, functions, constants, mut constant_types)!
397+ declared_kinds, struct_fields, functions, constants, public_constants, mut constant_types)!
396398 mut global_types := map [string ]string {}
397399 global_output := fastc_generate_global_declarations (sources, prefs, declared_types,
398- declared_kinds, struct_fields, functions, constants, constant_types, globals, mut
399- global_types)!
400+ declared_kinds, struct_fields, functions, constants, public_constants, constant_types,
401+ globals, mut global_types)!
400402 for constant_type in constant_types.values () {
401403 fastc_register_composite_type (constant_type, mut composite_types)
402404 }
@@ -419,6 +421,7 @@ fn generate_source_files(sources []FastcSourceFile, prefs &pref.Preferences) !st
419421 declared_kinds: declared_kinds
420422 struct_fields: struct_fields
421423 constants: constants
424+ public_constants: public_constants
422425 globals: globals
423426 used_function_names: used_function_names
424427 selfhost: prefs.building_v
@@ -842,16 +845,18 @@ fn collect_declared_types(source string, path string, module_name string, prefs
842845 }
843846}
844847
845- fn collect_constant_names (source string , path string , module_name string , prefs & pref.Preferences, mut constants map [string ]string ) ! {
848+ fn collect_constant_names (source string , path string , module_name string , prefs & pref.Preferences, mut constants map [string ]string , mut public_constants map [ string ] bool ) ! {
846849 mut file_set := token.FileSet.new ()
847850 mut file := file_set.add_file (path, source.len)
848851 file.index_lines (source)
849852 mut scan := scanner.new_scanner (prefs, .normal)
850853 scan.init (file, source)
851854 mut brace_depth := 0
855+ mut previous_tok := token.Token.unknown
852856 mut tok := scan.scan ()
853857 for tok != .eof {
854858 if brace_depth == 0 && tok == .key_const {
859+ is_public := previous_tok == .key_pub
855860 tok = scan.scan ()
856861 if tok == .lpar {
857862 tok = scan.scan ()
@@ -868,7 +873,8 @@ fn collect_constant_names(source string, path string, module_name string, prefs
868873 continue
869874 }
870875 if nested_depth == 0 && at_declaration_start && tok == .name {
871- fastc_register_constant (module_name, scan.lit, mut constants)
876+ fastc_register_constant (module_name, scan.lit, is_public, mut constants, mut
877+ public_constants)
872878 at_declaration_start = false
873879 }
874880 if tok in [.lpar, .lsbr, .lcbr] {
@@ -883,21 +889,26 @@ fn collect_constant_names(source string, path string, module_name string, prefs
883889 if tok != .name {
884890 return error ('fastc parser does not support constant declaration in ${path }' )
885891 }
886- fastc_register_constant (module_name, scan.lit, mut constants)
892+ fastc_register_constant (module_name, scan.lit, is_public, mut constants, mut
893+ public_constants)
887894 continue
888895 }
889896 if tok == .lcbr {
890897 brace_depth++
891898 } else if tok == .rcbr && brace_depth > 0 {
892899 brace_depth--
893900 }
901+ previous_tok = tok
894902 tok = scan.scan ()
895903 }
896904}
897905
898- fn fastc_register_constant (module_name string , name string , mut constants map [string ]string ) {
906+ fn fastc_register_constant (module_name string , name string , is_public bool , mut constants map [string ]string , mut public_constants map [ string ] bool ) {
899907 key := fastc_constant_key (module_name, name)
900908 constants[key] = fastc_c_constant_name (module_name, name)
909+ if is_public {
910+ public_constants[key] = true
911+ }
901912}
902913
903914fn collect_global_names (source string , path string , module_name string , prefs & pref.Preferences, mut globals map [string ]string ) ! {
@@ -941,30 +952,31 @@ fn collect_global_names(source string, path string, module_name string, prefs &p
941952 }
942953}
943954
944- fn 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 , functions map [string ]FastcFunctionSignature, constants map [string ]string , constant_types map [string ]string , globals map [string ]string , mut global_types map [string ]string ) ! FastcGlobalDeclarations {
955+ fn 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 , 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 {
945956 mut out := strings.new_builder (1024 )
946957 mut initializers := strings.new_builder (1024 )
947958 for source_file in sources {
948959 mut file_set := token.FileSet.new ()
949960 mut file := file_set.add_file (source_file.path, source_file.source.len)
950961 file.index_lines (source_file.source)
951962 mut gen := Parser{
952- prefs: unsafe { prefs }
953- path: source_file.path
954- module_name: source_file.header.module_name
955- imports: source_file.header.imports
956- declared_types: declared_types
957- declared_kinds: declared_kinds
958- struct_fields: struct_fields
959- constants: constants
960- globals: globals
961- selfhost: prefs.building_v
962- s: scanner.new_scanner (prefs, .normal)
963- out: strings.new_builder (0 )
964- protos: strings.new_builder (0 )
965- functions: functions
966- constant_types: constant_types
967- global_types: global_types
963+ prefs: unsafe { prefs }
964+ path: source_file.path
965+ module_name: source_file.header.module_name
966+ imports: source_file.header.imports
967+ declared_types: declared_types
968+ declared_kinds: declared_kinds
969+ struct_fields: struct_fields
970+ constants: constants
971+ public_constants: public_constants
972+ globals: globals
973+ selfhost: prefs.building_v
974+ s: scanner.new_scanner (prefs, .normal)
975+ out: strings.new_builder (0 )
976+ protos: strings.new_builder (0 )
977+ functions: functions
978+ constant_types: constant_types
979+ global_types: global_types
968980 }
969981 gen.s.init (file, source_file.source)
970982 gen.next ()
@@ -1053,27 +1065,28 @@ fn (mut g Parser) parse_global_declaration(mut out strings.Builder, mut initiali
10531065 g.skip_semicolons ()
10541066}
10551067
1056- fn fastc_generate_constant_declarations (sources []FastcSourceFile, prefs & pref.Preferences, declared_types map [string ]bool , declared_kinds map [string ]FastcDeclaredTypeKind, struct_fields map [string ]map [string ]string , functions map [string ]FastcFunctionSignature, constants map [string ]string , mut constant_types map [string ]string ) ! string {
1068+ fn fastc_generate_constant_declarations (sources []FastcSourceFile, prefs & pref.Preferences, declared_types map [string ]bool , declared_kinds map [string ]FastcDeclaredTypeKind, struct_fields map [string ]map [string ]string , functions map [string ]FastcFunctionSignature, constants map [string ]string , public_constants map [ string ] bool , mut constant_types map [string ]string ) ! string {
10571069 mut out := strings.new_builder (4096 )
10581070 for source_file in sources {
10591071 mut file_set := token.FileSet.new ()
10601072 mut file := file_set.add_file (source_file.path, source_file.source.len)
10611073 file.index_lines (source_file.source)
10621074 mut gen := Parser{
1063- prefs: unsafe { prefs }
1064- path: source_file.path
1065- module_name: source_file.header.module_name
1066- imports: source_file.header.imports
1067- declared_types: declared_types
1068- declared_kinds: declared_kinds
1069- struct_fields: struct_fields
1070- constants: constants
1071- selfhost: prefs.building_v
1072- s: scanner.new_scanner (prefs, .normal)
1073- out: strings.new_builder (256 )
1074- protos: strings.new_builder (0 )
1075- functions: functions
1076- constant_types: constant_types
1075+ prefs: unsafe { prefs }
1076+ path: source_file.path
1077+ module_name: source_file.header.module_name
1078+ imports: source_file.header.imports
1079+ declared_types: declared_types
1080+ declared_kinds: declared_kinds
1081+ struct_fields: struct_fields
1082+ constants: constants
1083+ public_constants: public_constants
1084+ selfhost: prefs.building_v
1085+ s: scanner.new_scanner (prefs, .normal)
1086+ out: strings.new_builder (256 )
1087+ protos: strings.new_builder (0 )
1088+ functions: functions
1089+ constant_types: constant_types
10771090 }
10781091 gen.s.init (file, source_file.source)
10791092 gen.next ()
@@ -3892,17 +3905,26 @@ fn (mut g Parser) parse_for() !bool {
38923905 g.next ()
38933906 start := g.read_expression ([token.Token.dotdot, token.Token.lcbr])!
38943907 start_expression_type := g.last_expression_type
3908+ start_expression := g.last_expression.clone ()
38953909 if g.tok == .dotdot {
38963910 if item_is_mut || value_name != '' {
38973911 return g.unsupported ('mutable or two-value range loop' )
38983912 }
38993913 g.next ()
39003914 end := g.read_expression ([token.Token.lcbr])!
39013915 end_expression_type := g.last_expression_type
3916+ end_expression := g.last_expression.clone ()
39023917 if ! fastc_is_integer_expression_type (start_expression_type)
39033918 || ! fastc_is_integer_expression_type (end_expression_type) {
39043919 return g.unsupported ('range bounds of types `${start_expression_type }` and `${end_expression_type }` must both be integers' )
39053920 }
3921+ if start_value := fastc_integer_literal_value (start_expression) {
3922+ if end_value := fastc_integer_literal_value (end_expression) {
3923+ if start_value > = end_value {
3924+ return g.unsupported ('empty range: `${start_expression [0 ].lit } .. ${end_expression [0 ].lit }` will never execute' )
3925+ }
3926+ }
3927+ }
39063928 g.expect (.lcbr)!
39073929 start_name := g.temporary_name ('range_start' )
39083930 end_name := g.temporary_name ('range_end' )
@@ -4015,6 +4037,7 @@ fn (mut g Parser) parse_for() !bool {
40154037 }
40164038 if g.tok in [.decl_assign, .assign] {
40174039 is_declaration := g.tok == .decl_assign
4040+ mut assignment_type := ''
40184041 if is_declaration && name in g.locals {
40194042 return g.unsupported ('redeclaration of `${name }`' )
40204043 }
@@ -4025,16 +4048,28 @@ fn (mut g Parser) parse_for() !bool {
40254048 if ! local.is_mut {
40264049 return g.unsupported ('assignment to immutable loop variable `${name }`' )
40274050 }
4051+ assignment_type = if local.is_reference {
4052+ local.typ.trim_right ('*' )
4053+ } else {
4054+ local.typ
4055+ }
40284056 }
40294057 g.next ()
40304058 initial := g.read_expression ([token.Token.semicolon])!
4059+ initial_expression_type := g.last_expression_type
40314060 initial_type := fastc_normalize_inferred_type (g.last_expression_type)
40324061 g.expect (.semicolon)!
40334062 if is_declaration {
40344063 g.locals[name] = FastcLocal{
40354064 is_mut: true
40364065 typ: initial_type
40374066 }
4067+ } else if initial_expression_type == '' || assignment_type == '' {
4068+ return g.unsupported ('unverifiable assignment type for `${name }`' )
4069+ } else if ! fastc_call_types_are_compatible (initial_expression_type, assignment_type)
4070+ && ! (g.selfhost
4071+ && g.selfhost_types_are_compatible (initial_expression_type, assignment_type)) {
4072+ return g.unsupported ('assignment of type `${initial_expression_type }` to `${name }` of type `${assignment_type }`' )
40384073 }
40394074 condition := g.read_expression ([token.Token.semicolon])!
40404075 g.require_boolean_condition ('for' )!
@@ -5213,7 +5248,13 @@ fn (mut g Parser) read_expression_with_prefix(prefix string, stops []token.Token
52135248 module_separator := g.tok == .dot && previous_token == .name && (previous_lit in g.imports
52145249 || previous_lit == 'C' || (g.selfhost && previous_lit ! in g.locals
52155250 && g.is_enum_type_name (previous_lit)))
5216- mut piece := g.expression_token (previous_token, previous_lit)!
5251+ qualified_name_owner := if g.tok == .name && previous_token == .dot
5252+ && expression_tokens.len > = 3 {
5253+ expression_tokens[expression_tokens.len - 3 ].lit
5254+ } else {
5255+ ''
5256+ }
5257+ mut piece := g.expression_token (previous_token, previous_lit, qualified_name_owner)!
52175258 if g.tok == .name && previous_token == .dot {
52185259 mut method_lookahead := g.s
52195260 if method_lookahead.scan () == .lpar {
@@ -8892,10 +8933,10 @@ fn fastc_expression_list_items(tokens []FastcExpressionToken, start int, end int
88928933 return result
88938934}
88948935
8895- fn (g &Parser) expression_token (previous token.Token, previous_lit string ) ! string {
8936+ fn (g &Parser) expression_token (previous token.Token, previous_lit string , qualified_name_owner string ) ! string {
88968937 return match g.tok {
88978938 .name {
8898- g.expression_name (previous)!
8939+ g.expression_name (previous, qualified_name_owner )!
88998940 }
89008941 .number {
89018942 if g.selfhost {
@@ -8978,7 +9019,15 @@ fn (g &Parser) nil_expression() !string {
89789019 return 'NULL'
89799020}
89809021
8981- fn (g &Parser) expression_name (previous token.Token) ! string {
9022+ fn (g &Parser) expression_name (previous token.Token, qualified_name_owner string ) ! string {
9023+ if previous == .dot {
9024+ if imported_module := g.imports[qualified_name_owner] {
9025+ constant_key := fastc_constant_key (imported_module, g.lit)
9026+ if constant_key in g.constants && constant_key ! in g.public_constants {
9027+ return g.unsupported ('private constant `${g .lit }` from imported module `${imported_module }`' )
9028+ }
9029+ }
9030+ }
89829031 g.validate_expression_name (g.lit, previous)!
89839032 return g.resolved_expression_name (g.lit, previous)
89849033}
@@ -9944,6 +9993,14 @@ fn fastc_number_expression_type(literal string) string {
99449993 return 'integer literal'
99459994}
99469995
9996+ fn fastc_integer_literal_value (tokens []FastcExpressionToken) ? i64 {
9997+ if tokens.len != 1 || tokens[0 ].tok != .number
9998+ || fastc_number_expression_type (tokens[0 ].lit) != 'integer literal' {
9999+ return none
10000+ }
10001+ return tokens[0 ].lit.replace ('_' , '' ).i64 ()
10002+ }
10003+
994710004fn fastc_common_arithmetic_type (left string , right string ) string {
994810005 if left == right && fastc_is_numeric_expression_type (left) {
994910006 return left
0 commit comments