@@ -55,35 +55,69 @@ static void v_fastc_println_unsigned(unsigned long long value) { printf("%llu\n"
5555struct Parser {
5656 path string
5757mut :
58- s scanner.Scanner
59- tok token.Token
60- lit string
61- out strings.Builder
62- protos strings.Builder
63- indent int
64- in_main bool
65- has_main bool
66- temp_id int
67- locals map [string ]bool
58+ s scanner.Scanner
59+ tok token.Token
60+ lit string
61+ out strings.Builder
62+ protos strings.Builder
63+ indent int
64+ in_main bool
65+ has_main bool
66+ temp_id int
67+ locals map [string ]bool
68+ functions map [string ]bool
6869}
6970
7071// generate scans V source and emits C as each declaration and statement is consumed. It does
7172// not construct an AST or invoke semantic type checking. Unsupported syntax is returned as an
7273// error; FastC never retries through an AST-based backend.
7374pub fn generate (source string , path string , prefs & pref.Preferences) ! string {
75+ functions := collect_function_names (source, path, prefs)!
7476 mut file_set := token.FileSet.new ()
7577 mut file := file_set.add_file (path, source.len)
7678 file.index_lines (source)
7779 mut gen := Parser{
78- path: path
79- s: scanner.new_scanner (prefs, .normal)
80- out: strings.new_builder (source.len)
81- protos: strings.new_builder (256 )
80+ path: path
81+ s: scanner.new_scanner (prefs, .normal)
82+ out: strings.new_builder (source.len)
83+ protos: strings.new_builder (256 )
84+ functions: functions
8285 }
8386 gen.s.init (file, source)
8487 return gen.run ()
8588}
8689
90+ fn collect_function_names (source string , path string , prefs & pref.Preferences) ! map [string ]bool {
91+ mut file_set := token.FileSet.new ()
92+ mut file := file_set.add_file (path, source.len)
93+ file.index_lines (source)
94+ mut scan := scanner.new_scanner (prefs, .normal)
95+ scan.init (file, source)
96+ mut functions := map [string ]bool {}
97+ mut brace_depth := 0
98+ mut tok := scan.scan ()
99+ for tok != .eof {
100+ if tok == .key_fn && brace_depth == 0 {
101+ tok = scan.scan ()
102+ if tok == .name {
103+ name := scan.lit
104+ if name in functions {
105+ return error ('fastc parser does not support duplicate function `${name }` in ${path }' )
106+ }
107+ functions[name] = true
108+ }
109+ continue
110+ }
111+ if tok == .lcbr {
112+ brace_depth++
113+ } else if tok == .rcbr && brace_depth > 0 {
114+ brace_depth--
115+ }
116+ tok = scan.scan ()
117+ }
118+ return functions
119+ }
120+
87121fn (mut g Parser) run () ! string {
88122 g.next ()
89123 for g.tok != .eof {
@@ -417,6 +451,9 @@ fn (mut g Parser) parse_for() ! {
417451 name := g.lit
418452 g.next ()
419453 if g.tok == .key_in {
454+ if name in g.locals {
455+ return g.unsupported ('redeclaration of `${name }`' )
456+ }
420457 g.next ()
421458 start := g.read_expression ([token.Token.dotdot])!
422459 g.expect (.dotdot)!
@@ -428,16 +465,22 @@ fn (mut g Parser) parse_for() ! {
428465 g.write_line ('__typeof__((${start })) ${start_name } = (${start });' )
429466 g.write_line ('__typeof__((${end })) ${end_name } = (${end });' )
430467 g.write_line ('for (__typeof__((${start_name })) ${name } = (${start_name }); ${name } < (${end_name }); ${name }++) {' )
468+ g.locals[name] = false
431469 g.indent++
432470 g.parse_block_body ()!
433471 g.indent--
472+ g.locals.delete (name)
434473 g.write_line ('}' )
435474 return
436475 }
437476 if g.tok == .decl_assign {
477+ if name in g.locals {
478+ return g.unsupported ('redeclaration of `${name }`' )
479+ }
438480 g.next ()
439481 initial := g.read_expression ([token.Token.semicolon])!
440482 g.expect (.semicolon)!
483+ g.locals[name] = true
441484 condition := g.read_expression ([token.Token.semicolon])!
442485 g.expect (.semicolon)!
443486 update := g.read_expression ([token.Token.lcbr])!
@@ -446,9 +489,11 @@ fn (mut g Parser) parse_for() ! {
446489 g.indent++
447490 g.parse_block_body ()!
448491 g.indent--
492+ g.locals.delete (name)
449493 g.write_line ('}' )
450494 return
451495 }
496+ g.validate_expression_name (name, .unknown)!
452497 condition := g.read_expression_with_prefix (name, [token.Token.lcbr])!
453498 g.expect (.lcbr)!
454499 g.write_line ('while (${condition }) {' )
@@ -507,6 +552,7 @@ fn (mut g Parser) parse_simple_statement() ! {
507552 && (name ! in g.locals || ! g.locals[name]) {
508553 return g.unsupported ('mutation of immutable or unknown name `${name }`' )
509554 }
555+ g.validate_expression_name (name, .unknown)!
510556 expression :=
511557 g.read_expression_with_prefix (name, [token.Token.semicolon, token.Token.rcbr])!
512558 g.consume_statement_end ()
@@ -564,6 +610,7 @@ fn (mut g Parser) read_expression_with_prefix(prefix string, stops []token.Token
564610 mut has_and_operator := false
565611 mut has_pipe_operator := false
566612 mut has_xor_operator := false
613+ mut previous_token := token.Token.unknown
567614 for g.tok != .eof {
568615 if paren_depth == 0 && g.tok in stops {
569616 break
@@ -629,7 +676,7 @@ fn (mut g Parser) read_expression_with_prefix(prefix string, stops []token.Token
629676 // levels and also orders + and - above &. Reject ambiguous token streams.
630677 return g.unsupported ('mixed operator precedence' )
631678 }
632- piece := g.expression_token ()!
679+ piece := g.expression_token (previous_token )!
633680 if result.len > 0 && fastc_needs_space (result.last (), piece) {
634681 result.write_u8 (` ` )
635682 }
@@ -646,6 +693,7 @@ fn (mut g Parser) read_expression_with_prefix(prefix string, stops []token.Token
646693 }
647694 else {}
648695 }
696+ previous_token = g.tok
649697 g.next ()
650698 }
651699 if paren_depth != 0 {
@@ -654,9 +702,9 @@ fn (mut g Parser) read_expression_with_prefix(prefix string, stops []token.Token
654702 return result.str ().trim_space ()
655703}
656704
657- fn (g &Parser) expression_token () ! string {
705+ fn (g &Parser) expression_token (previous token.Token ) ! string {
658706 return match g.tok {
659- .name { g.expression_name ()! }
707+ .name { g.expression_name (previous )! }
660708 .number { fastc_c_number (g.lit)! }
661709 .string { fastc_c_string (g.lit)! }
662710 .char { g.unsupported ('rune or C character literals' ) }
@@ -671,14 +719,23 @@ fn (g &Parser) expression_token() !string {
671719 }
672720}
673721
674- fn (g &Parser) expression_name () ! string {
675- if g.lit == 'charptr' {
722+ fn (g &Parser) expression_name (previous token.Token) ! string {
723+ g.validate_expression_name (g.lit, previous)!
724+ return g.lit
725+ }
726+
727+ fn (g &Parser) validate_expression_name (name string , previous token.Token) ! {
728+ if name == 'charptr' {
676729 return g.unsupported ('charptr expressions' )
677730 }
678- if g. lit == 'rune' {
731+ if name == 'rune' {
679732 return g.unsupported ('rune expressions' )
680733 }
681- return g.lit
734+ if previous == .dot || name in g.locals || name in g.functions
735+ || name in ['print' , 'println' , 'bool' , 'byte' , 'char' , 'f32' , 'f64' , 'i8' , 'i16' , 'i32' , 'i64' , 'int' , 'isize' , 'string' , 'u8' , 'u16' , 'u32' , 'u64' , 'uint' , 'usize' , 'voidptr' , 'byteptr' ] {
736+ return
737+ }
738+ return g.unsupported ('unresolved name `${name }`' )
682739}
683740
684741fn fastc_nondecimal_literal_is_type_sensitive (literal string ) bool {
0 commit comments