@@ -7,6 +7,8 @@ import { ResolverErrors } from "./errors";
7
7
8
8
const levenshtein = require ( 'fast-levenshtein' ) ;
9
9
10
+ const RedefineableTokenSentinel = new Token ( TokenType . AT , "" , 0 , 0 , 0 ) ;
11
+
10
12
class Environment {
11
13
source : string ;
12
14
// The parent of this environment
@@ -72,7 +74,7 @@ class Environment {
72
74
}
73
75
declareName ( identifier : Token ) {
74
76
const lookup = this . lookupNameCurrentEnv ( identifier ) ;
75
- if ( lookup !== undefined ) {
77
+ if ( lookup !== undefined && lookup !== RedefineableTokenSentinel ) {
76
78
throw new ResolverErrors . NameReassignmentError ( identifier . line , identifier . col ,
77
79
this . source ,
78
80
identifier . indexInSource ,
@@ -82,6 +84,19 @@ class Environment {
82
84
}
83
85
this . names . set ( identifier . lexeme , identifier ) ;
84
86
}
87
+ // Same as declareName but allowed to re-declare later.
88
+ declarePlaceholderName ( identifier : Token ) {
89
+ const lookup = this . lookupNameCurrentEnv ( identifier ) ;
90
+ if ( lookup !== undefined ) {
91
+ throw new ResolverErrors . NameReassignmentError ( identifier . line , identifier . col ,
92
+ this . source ,
93
+ identifier . indexInSource ,
94
+ identifier . indexInSource + identifier . lexeme . length ,
95
+ lookup ) ;
96
+
97
+ }
98
+ this . names . set ( identifier . lexeme , RedefineableTokenSentinel ) ;
99
+ }
85
100
suggestNameCurrentEnv ( identifier : Token ) : string | null {
86
101
const name = identifier . lexeme ;
87
102
let minDistance = Infinity ;
@@ -203,6 +218,13 @@ export class Resolver implements StmtNS.Visitor<void>, ExprNS.Visitor<void> {
203
218
return ;
204
219
}
205
220
if ( stmt instanceof Array ) {
221
+ // Resolve all top-level functions first. Python allows functions declared after
222
+ // another function to be used in that function.
223
+ for ( const st of stmt ) {
224
+ if ( st instanceof StmtNS . FunctionDef ) {
225
+ this . environment ?. declarePlaceholderName ( st . name ) ;
226
+ }
227
+ }
206
228
for ( const st of stmt ) {
207
229
st . accept ( this ) ;
208
230
}
0 commit comments