コード例 #1
0
ファイル: DoNode.cs プロジェクト: GlaireDaggers/cozi-lang
        public override void Emit(ILGeneratorContext context)
        {
            if (Condition == null)
            {
                // special case: do {} (with no while clause) is a non-looping block that can be broken out of using either "break" or "continue"
                var loopTop = context.Function.AppendBlock(true);
                var loopEnd = context.Function.AppendBlock();

                context.Function.Current = loopTop;

                context.Function.PushLoopContext(loopEnd, loopEnd);
                Body.Emit(context);
                context.Function.Current.EmitJmp(loopEnd);
                context.Function.PopLoopContext();

                context.Function.Current = loopEnd;
            }
            else
            {
                var loopTop      = context.Function.AppendBlock(true);
                var loopContinue = context.Function.AppendBlock();
                var loopEnd      = context.Function.AppendBlock();

                context.Function.Current = loopTop;

                context.Function.PushLoopContext(loopContinue, loopEnd);
                Body.Emit(context);
                context.Function.Current.EmitJmp(loopContinue);
                context.Function.PopLoopContext();

                context.Function.Current = loopContinue;

                var conditionType = Condition.EmitLoad(context);
                if (conditionType is BooleanTypeInfo)
                {
                    context.Function.Current.EmitBra(loopEnd);
                    context.Function.Current.EmitJmp(loopTop);
                }
                else
                {
                    context.Errors.Add(new CompileError(Condition.Source, "Expected boolean expression"));
                }

                context.Function.Current = loopEnd;
            }
        }
コード例 #2
0
ファイル: WhileNode.cs プロジェクト: GlaireDaggers/cozi-lang
        public override void Emit(ILGeneratorContext context)
        {
            var loopTop = context.Function.AppendBlock(true);
            var loopEnd = context.Function.AppendBlock();

            context.Function.Current = loopTop;
            var conditionType = Condition.EmitLoad(context);
            if(conditionType is BooleanTypeInfo)
            {
                context.Function.PushLoopContext(loopTop, loopEnd);

                context.Function.Current.EmitBra(loopEnd);
                Body.Emit(context);
                context.Function.Current.EmitJmp(loopTop);

                context.Function.PopLoopContext();
            }
            else
            {
                context.Errors.Add(new CompileError(Condition.Source, "Expected boolean expression"));
            }

            context.Function.Current = loopEnd;
        }
コード例 #3
0
ファイル: IfNode.cs プロジェクト: GlaireDaggers/cozi-lang
        public override void Emit(ILGeneratorContext context)
        {
            // wait, is condition a const? in that case we can just pick the if or else clause ahead of time and eliminate the branch
            if (Condition.IsConst(context.Module))
            {
                object val = Condition.VisitConst(context.Module);

                if (val is bool)
                {
                    bool b = (bool)val;
                    if (b)
                    {
                        Body.Emit(context);
                    }
                    else if (Else != null)
                    {
                        Else.Emit(context);
                    }
                }
                else
                {
                    context.Errors.Add(new CompileError(Condition.Source, "Condition expression must be a boolean"));
                }

                return;
            }

            var innerType = Condition.GetLoadType(context);

            if (innerType.Kind != TypeKind.Boolean)
            {
                context.Errors.Add(new CompileError(Condition.Source, "Condition expression must be a boolean"));
            }
            else
            {
                Condition.EmitLoad(context);
            }

            if (Else != null)
            {
                var ifBlock   = context.Function.Current;
                var elseBlock = context.Function.InsertBlock(ifBlock);
                var endBlock  = context.Function.InsertBlock(elseBlock);

                context.Function.Current = ifBlock;
                ifBlock.EmitBra(elseBlock);
                Body.Emit(context);
                ifBlock.EmitJmp(endBlock);

                context.Function.Current = elseBlock;
                Else.Emit(context);
                elseBlock.EmitJmp(endBlock);

                context.Function.Current = endBlock;
            }
            else
            {
                var ifBlock  = context.Function.Current;
                var endBlock = context.Function.InsertBlock(ifBlock);

                context.Function.Current = ifBlock;
                context.Function.Current.EmitBra(endBlock);
                Body.Emit(context);
                context.Function.Current.EmitJmp(endBlock);

                context.Function.Current = endBlock;
            }
        }
コード例 #4
0
        public override void Emit(ILGeneratorContext context)
        {
            context.Function.PushLocalsFrame();

            // is this a const array?
            if (Range.IsConst(context.Module))
            {
                object   val     = Range.VisitConst(context.Module);
                TypeInfo valType = TypeUtility.GetConstType(val, context.Context);

                if (valType is StaticArrayTypeInfo staticArrayType)
                {
                    System.Array array = (System.Array)val;

                    string iterId = Iterator.Source.Value.ToString();
                    if (context.Module.HasConst(iterId))
                    {
                        context.Errors.Add(new CompileError(Iterator.Source, $"Tried to emit temporary const {Iterator.Source.Value} here but a const already exists with that name. Consider renaming your iterator to avoid a collision"));
                    }

                    if (staticArrayType.ArraySize >= UNROLL_MAX)
                    {
                        context.Errors.Add(new CompileError(Range.Source, $"TODO: FIXME! We should avoid unrolling arrays that are too big, but currently don't have any mechanism for indexing a const array otherwise"));
                    }

                    // optimization: because we know the array's contents ahead of time, we can just unroll the loop and substitute a temporary const
                    for (int i = 0; i < staticArrayType.ArraySize; i++)
                    {
                        context.Module.Constants[iterId] = array.GetValue(i);
                        Body.Emit(context);
                    }

                    context.Module.Constants.Remove(iterId);
                }
                else
                {
                    context.Errors.Add(new CompileError(Range.Source, "Cannot iterate this expression"));
                }
            }
            // special-case handling of range expressions as an optimization
            else if (Range is RangeNode rangeExpr)
            {
                var iterator = context.Function.EmitLocal($"{Iterator.Source.Value}", context.Context.GlobalTypes.GetType("int"));
                var step     = context.Function.EmitTmpLocal(context.Context.GlobalTypes.GetType("int"));
                var max      = context.Function.EmitTmpLocal(context.Context.GlobalTypes.GetType("int"));

                // load starting value into iterator, ending value into max
                var minType = rangeExpr.Min.EmitLoad(context);
                TypeUtility.ImplicitCast(context, minType, context.Context.GlobalTypes.GetType("int"), rangeExpr.Min.Source);
                context.Function.Current.EmitStLoc(iterator);

                var maxType = rangeExpr.Max.EmitLoad(context);
                TypeUtility.ImplicitCast(context, maxType, context.Context.GlobalTypes.GetType("int"), rangeExpr.Max.Source);
                context.Function.Current.EmitStLoc(max);

                // calculate step (+1 or -1)
                context.Function.Current.EmitLdLoc(max);
                context.Function.Current.EmitLdLoc(iterator);
                context.Function.Current.EmitSubI(IntegerWidth.I32);
                context.Function.Current.EmitLdConstI(0);
                context.Function.Current.EmitCmpGe(IntegerWidth.I32);

                var currentBlock = context.Function.Current;
                var nextBlock    = context.Function.InsertBlock(currentBlock);
                var loopTop      = context.Function.InsertBlock(nextBlock);
                var loopIter     = context.Function.InsertBlock(loopTop);
                var loopEnd      = context.Function.InsertBlock(loopIter);

                currentBlock.EmitBra(nextBlock);
                currentBlock.EmitLdConstI(1);
                currentBlock.EmitStLoc(step);
                currentBlock.EmitJmp(loopTop);
                nextBlock.EmitLdConstI(-1);
                nextBlock.EmitStLoc(step);
                nextBlock.EmitJmp(loopTop);

                // now we can loop
                loopTop.EmitLdLoc(iterator);
                loopTop.EmitLdLoc(max);
                loopTop.EmitCmpLe(IntegerWidth.I32);
                loopTop.EmitBra(loopEnd);

                // emit body
                context.Function.Current = loopTop;
                context.Function.PushLoopContext(loopIter, loopEnd);
                Body.Emit(context);
                context.Function.LoopEscapeStack.Pop();

                // increment or decrement iterator and jump back to loop top
                context.Function.Current.EmitJmp(loopIter);
                context.Function.Current = loopIter;
                context.Function.Current.EmitLdLoc(iterator);
                context.Function.Current.EmitLdLoc(step);
                context.Function.Current.EmitAddI(IntegerWidth.I32);
                context.Function.Current.EmitStLoc(iterator);
                context.Function.Current.EmitJmp(loopTop);

                context.Function.Current = loopEnd;
            }
            else if (Range.GetLoadType(context) is StaticArrayTypeInfo staticArray)
            {
                if (staticArray.ArraySize <= UNROLL_MAX)
                {
                    // optimization: because we know the array's length ahead of time, we can just unroll the loop
                    var iterator = context.Function.EmitLocal($"{Iterator.Source.Value}", staticArray.ElementType);
                    var array    = context.Function.EmitTmpLocal(staticArray);

                    // TODO: should check and see if we can directly address the array expression
                    // if so, we can eliminate this temp store
                    Range.EmitLoad(context);
                    context.Function.Current.EmitStLoc(array);

                    for (int i = 0; i < staticArray.ArraySize; i++)
                    {
                        context.Function.Current.EmitLdLocPtr(array);
                        context.Function.Current.EmitLdConstI(i);
                        context.Function.Current.EmitLdElem(staticArray.ElementType);
                        context.Function.Current.EmitStLoc(iterator);

                        Body.Emit(context);
                    }
                }
                else
                {
                    var iterator = context.Function.EmitLocal($"{Iterator.Source.Value}", staticArray.ElementType);
                    var array    = context.Function.EmitTmpLocal(staticArray);
                    var idx      = context.Function.EmitTmpLocal(context.Context.GlobalTypes.GetType("int"));
                    var len      = context.Function.EmitTmpLocal(context.Context.GlobalTypes.GetType("int"));

                    // TODO: should check and see if we can directly address the array expression
                    // if so, we can eliminate this temp store
                    Range.EmitLoad(context);
                    context.Function.Current.EmitStLoc(array);

                    // get array length and store in len
                    context.Function.Current.EmitLdConstI((int)staticArray.ArraySize);
                    context.Function.Current.EmitStLoc(len);

                    // initialize idx
                    context.Function.Current.EmitLdConstI(0);
                    context.Function.Current.EmitStLoc(idx);

                    // now we can loop
                    var loopTop  = context.Function.InsertBlock(context.Function.Current, true);
                    var loopIter = context.Function.InsertBlock(loopTop);
                    var loopEnd  = context.Function.InsertBlock(loopIter);

                    loopTop.EmitLdLoc(idx);
                    loopTop.EmitLdLoc(len);
                    loopTop.EmitCmpLt(IntegerWidth.I32);
                    loopTop.EmitBra(loopEnd);

                    // store element in iterator
                    loopTop.EmitLdLocPtr(array);
                    loopTop.EmitLdLoc(idx);
                    loopTop.EmitLdElem(staticArray);
                    loopTop.EmitStLoc(iterator);

                    // emit body
                    context.Function.Current = loopTop;
                    context.Function.PushLoopContext(loopIter, loopEnd);
                    Body.Emit(context);
                    context.Function.LoopEscapeStack.Pop();

                    // increment idx and jump back to loop top
                    context.Function.Current.EmitJmp(loopIter);
                    context.Function.Current = loopIter;
                    context.Function.Current.EmitLdLoc(idx);
                    context.Function.Current.EmitLdConstI(1);
                    context.Function.Current.EmitAddI(IntegerWidth.I32);
                    context.Function.Current.EmitStLoc(idx);
                    context.Function.Current.EmitJmp(loopTop);

                    context.Function.Current = loopEnd;
                }
            }
            else if (Range.GetLoadType(context) is DynamicArrayTypeInfo dynArray)
            {
                var iterator = context.Function.EmitLocal($"{Iterator.Source.Value}", dynArray.ElementType);
                var idx      = context.Function.EmitTmpLocal(context.Context.GlobalTypes.GetType("int"));
                var len      = context.Function.EmitTmpLocal(context.Context.GlobalTypes.GetType("int"));

                // get array length and store in len
                Range.EmitLoad(context);
                context.Function.Current.EmitLdLength(dynArray);
                context.Function.Current.EmitStLoc(len);

                // initialize idx
                context.Function.Current.EmitLdConstI(0);
                context.Function.Current.EmitStLoc(idx);

                // now we can loop
                var loopTop  = context.Function.InsertBlock(context.Function.Current, true);
                var loopIter = context.Function.InsertBlock(loopTop);
                var loopEnd  = context.Function.InsertBlock(loopIter);

                loopTop.EmitLdLoc(idx);
                loopTop.EmitLdLoc(len);
                loopTop.EmitCmpLt(IntegerWidth.I32);
                loopTop.EmitBra(loopEnd);

                // store element in iterator
                context.Function.Current = loopTop;

                Range.EmitLoad(context);
                loopTop.EmitLdLoc(idx);
                loopTop.EmitLdElem(dynArray);
                loopTop.EmitStLoc(iterator);

                // emit body
                context.Function.PushLoopContext(loopIter, loopEnd);
                Body.Emit(context);
                context.Function.LoopEscapeStack.Pop();

                // increment idx and jump back to loop top
                context.Function.Current.EmitJmp(loopIter);
                context.Function.Current = loopIter;
                context.Function.Current.EmitLdLoc(idx);
                context.Function.Current.EmitLdConstI(1);
                context.Function.Current.EmitAddI(IntegerWidth.I32);
                context.Function.Current.EmitStLoc(idx);
                context.Function.Current.EmitJmp(loopTop);

                context.Function.Current = loopEnd;
            }
            else if (Range.GetLoadType(context) is StringTypeInfo stringType)
            {
                var iterator = context.Function.EmitLocal($"{Iterator.Source.Value}", context.Context.GlobalTypes.GetType("char"));
                var idx      = context.Function.EmitTmpLocal(context.Context.GlobalTypes.GetType("int"));
                var len      = context.Function.EmitTmpLocal(context.Context.GlobalTypes.GetType("int"));

                // get string length and store in len
                Range.EmitLoad(context);
                context.Function.Current.EmitLdLength(stringType);
                context.Function.Current.EmitStLoc(len);

                // initialize idx
                context.Function.Current.EmitLdConstI(0);
                context.Function.Current.EmitStLoc(idx);

                // now we can loop
                var loopTop  = context.Function.InsertBlock(context.Function.Current, true);
                var loopIter = context.Function.InsertBlock(loopTop);
                var loopEnd  = context.Function.InsertBlock(loopIter);

                loopTop.EmitLdLoc(idx);
                loopTop.EmitLdLoc(len);
                loopTop.EmitCmpLt(IntegerWidth.I32);
                loopTop.EmitBra(loopEnd);

                // store element in iterator
                context.Function.Current = loopTop;

                Range.EmitLoad(context);
                loopTop.EmitLdLoc(idx);
                loopTop.EmitLdElem(context.Context.GlobalTypes.GetType("string"));
                loopTop.EmitStLoc(iterator);

                // emit body
                context.Function.PushLoopContext(loopIter, loopEnd);
                Body.Emit(context);
                context.Function.LoopEscapeStack.Pop();

                // increment idx and jump back to loop top
                context.Function.Current.EmitJmp(loopIter);
                context.Function.Current = loopIter;
                context.Function.Current.EmitLdLoc(idx);
                context.Function.Current.EmitLdConstI(1);
                context.Function.Current.EmitAddI(IntegerWidth.I32);
                context.Function.Current.EmitStLoc(idx);
                context.Function.Current.EmitJmp(loopTop);

                context.Function.Current = loopEnd;
            }
            else
            {
                context.Errors.Add(new CompileError(Range.Source, "Cannot iterate this expression"));
            }

            context.Function.PopLocalsFrame();
        }
コード例 #5
0
 public override void Emit(ILGeneratorContext context)
 {
     Inner.Emit(context);
 }