@@ -24,7 +24,8 @@ class FunctionDefinitionExpression : Expression, IClosureBuilder
2424 SymbolRef m_Env ;
2525
2626 SourceRef m_Begin , m_End ;
27-
27+ private ScriptLoadingContext lcontext ;
28+ List < FunctionDefinitionStatement . FunctionParamRef > paramnames ;
2829
2930 public FunctionDefinitionExpression ( ScriptLoadingContext lcontext , bool usesGlobalEnv )
3031 : this ( lcontext , false , usesGlobalEnv , false )
@@ -33,26 +34,43 @@ public FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool usesGlob
3334 public FunctionDefinitionExpression ( ScriptLoadingContext lcontext , bool pushSelfParam , bool isLambda )
3435 : this ( lcontext , pushSelfParam , false , isLambda )
3536 { }
36-
37-
37+
3838 private FunctionDefinitionExpression ( ScriptLoadingContext lcontext , bool pushSelfParam , bool usesGlobalEnv , bool isLambda )
3939 : base ( lcontext )
4040 {
41+ this . lcontext = lcontext ;
42+
4143 if ( m_UsesGlobalEnv = usesGlobalEnv )
4244 CheckTokenType ( lcontext , TokenType . Function ) ;
4345
46+
47+ // create scope
48+ // This needs to be up here to allow for arguments to correctly close over ENV
49+ // Arguments, however, must come before any other local definitions to avoid closing
50+ // over uninitialised variables. (Note for hoisting).
51+ lcontext . Scope . PushFunction ( this ) ;
52+
53+ if ( m_UsesGlobalEnv )
54+ {
55+ m_Env = lcontext . Scope . DefineLocal ( WellKnownSymbols . ENV ) ;
56+ }
57+ else
58+ {
59+ lcontext . Scope . ForceEnvUpValue ( ) ;
60+ }
61+
62+ // Parse arguments
4463 // here lexer should be at the '(' or at the '|'
4564 //Token openRound = CheckTokenType(lcontext, isLambda ? TokenType.Lambda : TokenType.Brk_Open_Round);
4665
4766 Token openRound ;
48- List < string > paramnames ;
4967 bool openCurly = false ;
5068 if ( isLambda )
5169 {
5270 openRound = lcontext . Lexer . Current ;
5371 lcontext . Lexer . Next ( ) ;
5472 if ( openRound . Type == TokenType . Name )
55- paramnames = new List < string > ( new [ ] { openRound . Text } ) ;
73+ paramnames = new List < FunctionDefinitionStatement . FunctionParamRef > ( new FunctionDefinitionStatement . FunctionParamRef [ ] { new FunctionDefinitionStatement . FunctionParamRef ( openRound . Text ) } ) ;
5674 else
5775 paramnames = BuildParamList ( lcontext , pushSelfParam , openRound ) ;
5876 }
@@ -77,19 +95,10 @@ private FunctionDefinitionExpression(ScriptLoadingContext lcontext, bool pushSel
7795
7896 m_Begin = openRound . GetSourceRefUpTo ( lcontext . Lexer . Current ) ;
7997
80- // create scope
81- lcontext . Scope . PushFunction ( this , m_HasVarArgs ) ;
82-
83- if ( m_UsesGlobalEnv )
84- {
85- m_Env = lcontext . Scope . DefineLocal ( WellKnownSymbols . ENV ) ;
86- }
87- else
88- {
89- lcontext . Scope . ForceEnvUpValue ( ) ;
90- }
9198
9299 m_ParamNames = DefineArguments ( paramnames , lcontext ) ;
100+
101+ if ( m_HasVarArgs ) lcontext . Scope . SetHasVarArgs ( ) ; //Moved here
93102
94103 if ( isLambda )
95104 m_Statement = CreateLambdaBody ( lcontext , arrowFunc ) ;
@@ -150,33 +159,61 @@ private Statement CreateBody(ScriptLoadingContext lcontext, bool openCurly)
150159 return s ;
151160 }
152161
153- private List < string > BuildParamList ( ScriptLoadingContext lcontext , bool pushSelfParam , Token openBracketToken )
162+ private List < FunctionDefinitionStatement . FunctionParamRef > BuildParamList ( ScriptLoadingContext lcontext , bool pushSelfParam , Token openBracketToken )
154163 {
155164 TokenType closeToken = openBracketToken . Type == TokenType . Lambda ? TokenType . Lambda : TokenType . Brk_Close_Round ;
156165
157- List < string > paramnames = new List < string > ( ) ;
166+ List < FunctionDefinitionStatement . FunctionParamRef > paramnames = new List < FunctionDefinitionStatement . FunctionParamRef > ( ) ;
158167
159168 // method decls with ':' must push an implicit 'self' param
160169 if ( pushSelfParam )
161- paramnames . Add ( lcontext . Syntax == ScriptSyntax . CLike ? "this" : "self" ) ;
170+ paramnames . Add ( lcontext . Syntax == ScriptSyntax . CLike ? new FunctionDefinitionStatement . FunctionParamRef ( "this" ) : new FunctionDefinitionStatement . FunctionParamRef ( "self" ) ) ;
162171
172+ bool parsingDefaultParams = false ;
163173 while ( lcontext . Lexer . Current . Type != closeToken )
164174 {
165175 Token t = lcontext . Lexer . Current ;
176+ bool nextAfterParamDeclr = true ;
166177
167178 if ( t . Type == TokenType . Name )
168179 {
169- paramnames . Add ( t . Text ) ;
180+ string paramName = t . Text ;
181+
182+ if ( lcontext . Lexer . PeekNext ( ) . Type == TokenType . Op_Assignment )
183+ {
184+ parsingDefaultParams = true ;
185+ lcontext . Lexer . Next ( ) ;
186+ lcontext . Lexer . Next ( ) ;
187+ Expression defaultVal = Expr ( lcontext ) ;
188+ nextAfterParamDeclr = false ;
189+
190+ paramnames . Add ( new FunctionDefinitionStatement . FunctionParamRef ( paramName , defaultVal ) ) ;
191+ }
192+ else
193+ {
194+ if ( parsingDefaultParams )
195+ {
196+ throw new SyntaxErrorException ( t , "after first parameter with default value a parameter without default value cannot be declared" , t . Text )
197+ {
198+ IsPrematureStreamTermination = ( t . Type == TokenType . Eof )
199+ } ;
200+ }
201+
202+ paramnames . Add ( new FunctionDefinitionStatement . FunctionParamRef ( paramName ) ) ;
203+ }
170204 }
171205 else if ( t . Type == TokenType . VarArgs )
172206 {
173207 m_HasVarArgs = true ;
174- paramnames . Add ( WellKnownSymbols . VARARGS ) ;
208+ paramnames . Add ( new FunctionDefinitionStatement . FunctionParamRef ( WellKnownSymbols . VARARGS ) ) ;
175209 }
176210 else
177211 UnexpectedTokenType ( t ) ;
178212
179- lcontext . Lexer . Next ( ) ;
213+ if ( nextAfterParamDeclr )
214+ {
215+ lcontext . Lexer . Next ( ) ;
216+ }
180217
181218 t = lcontext . Lexer . Current ;
182219
@@ -197,18 +234,18 @@ private List<string> BuildParamList(ScriptLoadingContext lcontext, bool pushSelf
197234 return paramnames ;
198235 }
199236
200- private SymbolRef [ ] DefineArguments ( List < string > paramnames , ScriptLoadingContext lcontext )
237+ private SymbolRef [ ] DefineArguments ( List < FunctionDefinitionStatement . FunctionParamRef > paramnames , ScriptLoadingContext lcontext )
201238 {
202239 HashSet < string > names = new HashSet < string > ( ) ;
203240
204241 SymbolRef [ ] ret = new SymbolRef [ paramnames . Count ] ;
205242
206243 for ( int i = paramnames . Count - 1 ; i >= 0 ; i -- )
207244 {
208- if ( ! names . Add ( paramnames [ i ] ) )
209- paramnames [ i ] = paramnames [ i ] + "@" + i . ToString ( ) ;
245+ if ( ! names . Add ( paramnames [ i ] . Name ) )
246+ paramnames [ i ] . Name = paramnames [ i ] . Name + "@" + i . ToString ( ) ;
210247
211- ret [ i ] = lcontext . Scope . DefineLocal ( paramnames [ i ] ) ;
248+ ret [ i ] = lcontext . Scope . DefineLocal ( paramnames [ i ] . Name ) ;
212249 }
213250
214251 return ret ;
@@ -243,6 +280,8 @@ public override DynValue Eval(ScriptExecutionContext context)
243280
244281 public int CompileBody ( ByteCode bc , string friendlyName )
245282 {
283+ //LoadingContext.Scope.PopFunction()
284+
246285 string funcName = friendlyName ?? ( "<" + this . m_Begin . FormatLocation ( bc . Script , true ) + ">" ) ;
247286
248287 bc . PushSourceRef ( m_Begin ) ;
@@ -265,8 +304,25 @@ public int CompileBody(ByteCode bc, string friendlyName)
265304 }
266305
267306 if ( m_ParamNames . Length > 0 )
307+ {
268308 bc . Emit_Args ( m_ParamNames ) ;
269309
310+ for ( int i = 0 ; i < m_ParamNames . Length ; i ++ )
311+ {
312+ FunctionDefinitionStatement . FunctionParamRef fr = paramnames [ i ] ;
313+ SymbolRef sr = m_ParamNames [ i ] ;
314+
315+ if ( fr . DefaultValue != null )
316+ {
317+ var jp = bc . Emit_JLclInit ( sr , - 1 ) ;
318+ fr . DefaultValue . CompilePossibleLiteral ( bc ) ;
319+ new SymbolRefExpression ( lcontext , sr ) . CompileAssignment ( bc , Operator . NotAnOperator , 0 , 0 ) ;
320+ bc . Emit_Pop ( ) ;
321+ bc . SetNumVal ( jp , bc . GetJumpPointForNextInstruction ( ) ) ;
322+ }
323+ }
324+ }
325+
270326 m_Statement . Compile ( bc ) ;
271327
272328 bc . PopSourceRef ( ) ;
0 commit comments