diff --git a/ssc/ast/nodes.flow.cs b/ssc/ast/nodes.flow.cs index 30938a1..3ac4541 100644 --- a/ssc/ast/nodes.flow.cs +++ b/ssc/ast/nodes.flow.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Linq; namespace arookas { @@ -30,14 +31,19 @@ namespace arookas { protected sunLoopNode(sunSourceLocation location) : base(location) { } - public void PushLoop(sunContext context) { + public sunLoop PushLoop(sunContext context) { var name = context.PopNameLabel(); if (name == null) { - context.Loops.Push(); + return context.Loops.Push(); } - else { - context.Loops.Push(name.Label.Value); + return context.Loops.Push(name.Label.Value); + } + public sunLoop PushLoop(sunContext context, sunLoopFlags flags) { + var name = context.PopNameLabel(); + if (name == null) { + return context.Loops.Push(flags); } + return context.Loops.Push(name.Label.Value, flags); } } @@ -49,16 +55,16 @@ namespace arookas { : base(location) { } public override void Compile(sunContext context) { - PushLoop(context); + var loop = PushLoop(context); var bodyPrologue = context.Text.OpenPoint(); - var continuePoint = context.Text.OpenPoint(); + loop.ContinuePoint = context.Text.OpenPoint(); Condition.Compile(context); var bodyEpilogue = context.Text.WriteJNE(); Body.Compile(context); context.Text.WriteJMP(bodyPrologue); context.Text.ClosePoint(bodyEpilogue); - var breakPoint = context.Text.OpenPoint(); - context.Loops.Pop(context, breakPoint, continuePoint); + loop.BreakPoint = context.Text.OpenPoint(); + context.Loops.Pop(context); } } @@ -70,16 +76,16 @@ namespace arookas { : base(location) { } public override void Compile(sunContext context) { - PushLoop(context); + var loop = PushLoop(context); var bodyPrologue = context.Text.OpenPoint(); Body.Compile(context); - var continuePoint = context.Text.OpenPoint(); + loop.ContinuePoint = context.Text.OpenPoint(); Condition.Compile(context); var bodyEpilogue = context.Text.WriteJNE(); context.Text.WriteJMP(bodyPrologue); context.Text.ClosePoint(bodyEpilogue); - var breakPoint = context.Text.OpenPoint(); - context.Loops.Pop(context, breakPoint, continuePoint); + loop.BreakPoint = context.Text.OpenPoint(); + context.Loops.Pop(context); } } @@ -94,18 +100,18 @@ namespace arookas { public override void Compile(sunContext context) { context.Scopes.Push(); - PushLoop(context); + var loop = PushLoop(context); TryCompile(Declaration, context); var bodyPrologue = context.Text.OpenPoint(); TryCompile(Condition, context); var bodyEpilogue = context.Text.WriteJNE(); Body.Compile(context); - var continuePoint = context.Text.OpenPoint(); + loop.ContinuePoint = context.Text.OpenPoint(); TryCompile(Iteration, context); context.Text.WriteJMP(bodyPrologue); context.Text.ClosePoint(bodyEpilogue); - var breakPoint = context.Text.OpenPoint(); - context.Loops.Pop(context, breakPoint, continuePoint); + loop.BreakPoint = context.Text.OpenPoint(); + context.Loops.Pop(context); context.Scopes.Pop(); } } diff --git a/ssc/loop stack.cs b/ssc/loop stack.cs index 9b42614..6e5d755 100644 --- a/ssc/loop stack.cs +++ b/ssc/loop stack.cs @@ -1,27 +1,48 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace arookas { class sunLoopStack { - Stack loops = new Stack(5); - sunLoop Top { get { return loops.Peek(); } } + Stack mLoops; - sunLoop this[string name] { get { return loops.FirstOrDefault(i => i.Name == name); } } - public int Count { get { return loops.Count; } } + sunLoop Top { get { return mLoops.Peek(); } } + sunLoop this[string name] { get { return mLoops.FirstOrDefault(i => i.Name == name); } } + public int Count { get { return mLoops.Count; } } - public void Push() { Push(null); } - public void Push(string name) { loops.Push(new sunLoop(name)); } - public void Pop(sunContext context, sunPoint breakPoint, sunPoint continuePoint) { - foreach (var _break in Top.Breaks) { - context.Text.ClosePoint(_break, breakPoint.Offset); - } - foreach (var _continue in Top.Continues) { - context.Text.ClosePoint(_continue, continuePoint.Offset); - } - loops.Pop(); + public sunLoopStack() { + mLoops = new Stack(5); } - public void Clear() { loops.Clear(); } + public sunLoop Push() { + return Push(new sunLoop()); + } + public sunLoop Push(sunLoopFlags flags) { + return Push(new sunLoop(flags)); + } + public sunLoop Push(string name) { + return Push(new sunLoop(name)); + } + public sunLoop Push(string name, sunLoopFlags flags) { + return Push(new sunLoop(name, flags)); + } + sunLoop Push(sunLoop loop) { + if (loop == null) { + throw new ArgumentNullException("loop"); + } + mLoops.Push(loop); + return loop; + } + public void Pop(sunContext context) { + if (Count < 1) { + return; + } + mLoops.Pop().Close(context); + } + + public void Clear() { + mLoops.Clear(); + } public bool AddBreak(sunPoint point) { return AddBreak(point, null); } public bool AddContinue(sunPoint point) { return AddContinue(point, null); } @@ -33,7 +54,7 @@ namespace arookas { if (loop == null) { return false; } - loop.Breaks.Add(point); + loop.AddBreak(point); return true; } public bool AddContinue(sunPoint point, string name) { @@ -44,24 +65,76 @@ namespace arookas { if (loop == null) { return false; } - loop.Continues.Add(point); + loop.AddContinue(point); return true; } - class sunLoop { - public string Name { get; private set; } - public List Breaks { get; private set; } - public List Continues { get; private set; } + } - public sunLoop() - : this(null) { + class sunLoop { + string mName; + List mBreaks, mContinues; + sunLoopFlags mFlags; + sunPoint mBreakPoint, mContinuePoint; + public string Name { get { return mName; } } + public bool HasName { get { return Name != null; } } + public sunPoint BreakPoint { get { return mBreakPoint; } set { mBreakPoint = value; } } + public sunPoint ContinuePoint { get { return mContinuePoint; } set { mContinuePoint = value; } } + + public sunLoop() { + mName = null; + mBreaks = new List(5); + mContinues = new List(5); + mFlags = sunLoopFlags.ConsumeBreak | sunLoopFlags.ConsumeContinue; + } + public sunLoop(sunLoopFlags flags) { + mFlags = flags; + } + public sunLoop(string name) { + mName = name; + } + public sunLoop(string name, sunLoopFlags flags) { + mName = name; + mFlags = flags; + } + + bool HasFlag(sunLoopFlags flags) { + return (mFlags & flags) != 0; + } + + public bool AddBreak(sunPoint point) { + if (!HasFlag(sunLoopFlags.ConsumeBreak)) { + return false; } - public sunLoop(string name) { - Name = name; - Breaks = new List(5); - Continues = new List(5); + mBreaks.Add(point); + return true; + } + public bool AddContinue(sunPoint point) { + if (!HasFlag(sunLoopFlags.ConsumeContinue)) { + return false; + } + mContinues.Add(point); + return true; + } + public void Close(sunContext context) { + if (HasFlag(sunLoopFlags.ConsumeBreak)) { + foreach (var b in mBreaks) { + context.Text.ClosePoint(b, mBreakPoint.Offset); + } + } + if (HasFlag(sunLoopFlags.ConsumeContinue)) { + foreach (var c in mContinues) { + context.Text.ClosePoint(c, mContinuePoint.Offset); + } } } } + + [Flags] + enum sunLoopFlags { + None = 0, + ConsumeBreak = 1, + ConsumeContinue = 2, + } }