BadScript 2
Loading...
Searching...
No Matches
BadForEachExpression.cs
Go to the documentation of this file.
9
14
19{
23 public readonly BadWordToken LoopVariable;
24
28 private readonly List<BadExpression> m_Body;
29
34
43 BadWordToken loopVariable,
44 IEnumerable<BadExpression> body,
45 BadSourcePosition position) : base(false,
46 position
47 )
48 {
49 Target = target;
50 LoopVariable = loopVariable;
51 m_Body = body.ToList();
52 }
53
57 public IEnumerable<BadExpression> Body => m_Body;
58
63 public void SetBody(IEnumerable<BadExpression> body)
64 {
65 m_Body.Clear();
66 m_Body.AddRange(body);
67 }
68
69
71 public override void Optimize()
72 {
74
75 for (int i = 0; i < m_Body.Count; i++)
76 {
78 }
79 }
80
82 public override IEnumerable<BadExpression> GetDescendants()
83 {
84 foreach (BadExpression expression in Target.GetDescendantsAndSelf())
85 {
86 yield return expression;
87 }
88
89 foreach (BadExpression descendant in m_Body.SelectMany(expression => expression.GetDescendantsAndSelf()))
90 {
91 yield return descendant;
92 }
93 }
94
102 public static (BadFunction moveNext, BadFunction getCurrent) FindEnumerator(
103 BadObject target,
104 BadExecutionContext context,
105 BadSourcePosition position)
106 {
107 if (!target.HasProperty("MoveNext", context.Scope))
108 {
109 throw new BadRuntimeException("Invalid enumerator", position);
110 }
111
112 if (target.GetProperty("MoveNext", context.Scope)
113 .Dereference(position) is not BadFunction moveNext)
114 {
115 throw new BadRuntimeException("Invalid enumerator", position);
116 }
117
118 if (!target.HasProperty("GetCurrent", context.Scope))
119 {
120 throw new BadRuntimeException("Invalid enumerator", position);
121 }
122
123 if (target.GetProperty("GetCurrent", context.Scope)
124 .Dereference(position) is BadFunction getCurrent)
125 {
126 return (moveNext, getCurrent);
127 }
128
129 throw new BadRuntimeException("Invalid enumerator", position);
130 }
131
132 public static IEnumerable<BadObject> Enumerate(BadExecutionContext context,
133 BadObject target,
134 BadSourcePosition position,
135 Func<Action, BadExecutionContext, BadObject, BadSourcePosition, IEnumerable<BadObject>> action)
136 {
137 if (target.HasProperty("GetEnumerator", context.Scope))
138 {
139 if (target.GetProperty("GetEnumerator", context.Scope)
140 .Dereference(position) is not BadFunction getEnumerator)
141 {
142 throw new BadRuntimeException("Invalid enumerator", position);
143 }
144
145 BadObject newTarget = BadObject.Null;
146
147 foreach (BadObject o in getEnumerator.Invoke(Array.Empty<BadObject>(), context))
148 {
149 yield return o;
150
151 newTarget = o;
152 }
153
154 if (newTarget == BadObject.Null)
155 {
156 throw BadRuntimeException.Create(context.Scope, $"Invalid enumerator: {target}", position);
157 }
158
159 target = newTarget.Dereference(position);
160 }
161
162 (BadFunction moveNext, BadFunction getCurrent) = FindEnumerator(target, context, position);
163
164 BadObject cond = BadObject.Null;
165
166 foreach (BadObject o in moveNext.Invoke(Array.Empty<BadObject>(), context))
167 {
168 cond = o;
169
170 yield return o;
171 }
172
173 IBadBoolean bRet = cond.Dereference(position) as IBadBoolean ??
174 throw new BadRuntimeException("While Condition is not a boolean", position);
175
176 while (bRet.Value)
177 {
178 using BadExecutionContext loopContext = new BadExecutionContext(context.Scope.CreateChild("ForEachLoop",
179 context.Scope,
180 null,
181 BadScopeFlags.Breakable |
182 BadScopeFlags.Continuable
183 )
184 );
185
186 BadObject current = BadObject.Null;
187
188 foreach (BadObject o in getCurrent.Invoke(Array.Empty<BadObject>(), loopContext))
189 {
190 current = o;
191
192 yield return o;
193 }
194
195 bool bBreak = false;
196
197 foreach (BadObject? o in action(() => bBreak = true, loopContext, current.Dereference(position), position))
198 {
199 yield return o;
200 }
201
202 if (bBreak)
203 {
204 break;
205 }
206
207 foreach (BadObject o in moveNext.Invoke(Array.Empty<BadObject>(), loopContext))
208 {
209 cond = o;
210
211 yield return o;
212 }
213
214 bRet = cond.Dereference(position) as IBadBoolean ??
215 throw BadRuntimeException.Create(context.Scope,
216 "Enumerator MoveNext did not return a boolean",
217 position
218 );
219 }
220 }
221
222 protected override IEnumerable<BadObject> InnerExecute(BadExecutionContext context)
223 {
224 BadObject target = BadObject.Null;
225
226 foreach (BadObject o in Target.Execute(context))
227 {
228 target = o;
229
230 yield return o;
231 }
232
233 target = target.Dereference(Position);
234
235 foreach (BadObject? o in Enumerate(context, target, Position, LoopBody))
236 {
237 yield return o;
238 }
239 }
240
241 private IEnumerable<BadObject> LoopBody(Action breakLoop, BadExecutionContext loopContext, BadObject current, BadSourcePosition position)
242 {
243 if (m_Body.Count != 0)
244 {
245 current = current.Dereference(position);
246 loopContext.Scope.DefineVariable(LoopVariable.Text, current);
247
248 foreach (BadObject o in loopContext.Execute(m_Body))
249 {
250 yield return o;
251 }
252
253 if (loopContext.Scope.IsBreak || loopContext.Scope.ReturnValue != null /*|| loopContext.Scope.IsError*/)
254 {
255 breakLoop();
256 }
257 }
258 }
259}
Describes a specific position inside a source file.
static BadExpression Optimize(BadExpression expr)
Optimizes the given expression.
Base Implementation for all Expressions used inside the Script.
IEnumerable< BadExpression > GetDescendantsAndSelf()
Returns all Descendants of the Expression and the Expression itself.
BadSourcePosition Position
The source Position of the Expression.
IEnumerable< BadObject > Execute(BadExecutionContext context)
Evaluates the Expression within the current Execution Context.
override void Optimize()
Uses the Constant Folding Optimizer to optimize the expression.
readonly BadWordToken LoopVariable
The Variable Name of the Current Loop iteration.
void SetBody(IEnumerable< BadExpression > body)
Sets the Body of the Loop.
BadExpression Target
The Enumerable/Enumerator Expression of the Loop.
static BadFunction BadFunction getCurrent FindEnumerator(BadObject target, BadExecutionContext context, BadSourcePosition position)
static BadFunction moveNext
Helper Function that returns the MoveNext/GetCurrent function of the Target.
override IEnumerable< BadObject > InnerExecute(BadExecutionContext context)
IEnumerable< BadObject > LoopBody(Action breakLoop, BadExecutionContext loopContext, BadObject current, BadSourcePosition position)
BadForEachExpression(BadExpression target, BadWordToken loopVariable, IEnumerable< BadExpression > body, BadSourcePosition position)
Constructor of the For Each Expression.
static IEnumerable< BadObject > Enumerate(BadExecutionContext context, BadObject target, BadSourcePosition position, Func< Action, BadExecutionContext, BadObject, BadSourcePosition, IEnumerable< BadObject > > action)
string Text
The Text Representation of the Token.
Definition BadToken.cs:27
The Execution Context. Every execution of a script needs a context the script is running in....
IEnumerable< BadObject > Execute(IEnumerable< BadExpression > expressions)
Executes an enumeration of expressions.
BadScope Scope
The Root Scope of the Context.
BadScope CreateChild(string name, BadScope? caller, bool? useVisibility, BadScopeFlags flags=BadScopeFlags.RootScope)
Creates a subscope of the current scope.
Definition BadScope.cs:597
bool IsBreak
Is true if the Break Keyword was set.
Definition BadScope.cs:172
BadObject? ReturnValue
The Return value of the scope.
Definition BadScope.cs:182
void DefineVariable(string name, BadObject value, BadScope? caller=null, BadPropertyInfo? info=null, BadObject[]? attributes=null)
Defines a new Variable in the current scope.
Definition BadScope.cs:784
static BadRuntimeException Create(BadScope? scope, string message)
Creates a new BadScriptException.
The Base Class for all BadScript Objects.
Definition BadObject.cs:14
virtual BadObjectReference GetProperty(string propName, BadScope? caller=null)
Returns a Reference to the Property with the given Name.
Definition BadObject.cs:141
virtual bool HasProperty(string propName, BadScope? caller=null)
Returns true if the object contains a given property or there exists an extension for the current Ins...
Definition BadObject.cs:130
static readonly BadObject Null
The Null Value for the BadScript Language.
Definition BadObject.cs:28
Implements a function that can be called from the script.
IEnumerable< BadObject > Invoke(BadObject[] args, BadExecutionContext caller)
Invokes the function with the specified arguments.
Implements the Interface for Native Boolean.
Definition IBadBoolean.cs:7
Contains Shared Data Structures and Functionality.
Contains the BadScript2 Constant Folding Optimizations.
Contains the Loop Expressions for the BadScript2 Language.
Contains the Reader Tokens for the BadScript2 Language.
Contains the Error Objects for the BadScript2 Language.
Contains Runtime Function Objects.
Contains the Native Runtime Objects.
Definition BadBoolean.cs:6
Contains the Runtime Objects.
Definition BadArray.cs:10
Contains the Runtime Implementation.
BadScopeFlags
Defines Different Behaviours for the Current Scope.