//This is an old typeId that was used to optimize small ranges (to generate them in-place). //It is currently not used, but in future it may be rejuvenated. private bool TryOptimizeRange(ElaRange range, LabelMap map, Hints hints) { if (range.First.Type != ElaNodeType.Primitive || (range.Second != null && range.Second.Type != ElaNodeType.Primitive) || range.Last.Type != ElaNodeType.Primitive) return false; var fst = (ElaPrimitive)range.First; var snd = range.Second != null ? (ElaPrimitive)range.Second : null; var lst = (ElaPrimitive)range.Last; if (fst.Value.LiteralType != ElaTypeCode.Integer || (snd != null && snd.Value.LiteralType != ElaTypeCode.Integer) || lst.Value.LiteralType != ElaTypeCode.Integer) return false; var fstVal = fst.Value.AsInteger(); var sndVal = snd != null ? snd.Value.AsInteger() : fstVal + 1; var lstVal = lst.Value.AsInteger(); var step = sndVal - fstVal; if (Math.Abs((fstVal - lstVal) / step) > 20) return false; cw.Emit(Op.Newlist); if (snd != null) { cw.Emit(Op.PushI4, fstVal); fstVal = sndVal; cw.Emit(Op.Cons); } for (;;) { cw.Emit(Op.PushI4, fstVal); cw.Emit(Op.Cons); fstVal += step; if (step > 0) { if (fstVal > lstVal) break; } else if (fstVal < lstVal) break; } cw.Emit(Op.Genfin); return true; }
//An entry method for range generation. Implementation of ranges are not provided by a compiler, //instead a particular data type implement ranges by providing an instance of Enum class. Functions //succ, enumFrom and enumFromTo are explicitly invoked by this method. private void CompileRange(ElaExpression parent, ElaRange range, LabelMap map, Hints hints) { AddLinePragma(range); var snd = AddVariable(); var fst = AddVariable(); //Compile the first element which should always be present. CompileExpression(range.First, map, Hints.None, range); PopVar(fst); //If the second element is missing we will calculate it using 'succ'. if (range.Second == null) { var sv = GetFunction("succ", range); PushVar(fst); PushVar(sv); cw.Emit(Op.Call); PopVar(snd); } else { CompileExpression(range.Second, map, Hints.None, range); PopVar(snd); } //If a last element is missing we need to generate an infinite range //using 'enumFrom' function. if (range.Last == null) { var sv = GetFunction("enumFrom", range); PushVar(snd); PushVar(fst); PushVar(sv); cw.Emit(Op.Call); cw.Emit(Op.Call); } else { //An ordinary strict range. var sv = GetFunction("enumFromTo", range); PushVar(snd); PushVar(fst); CompileExpression(range.Last, map, Hints.None, range); PushVar(sv); cw.Emit(Op.Call); cw.Emit(Op.Call); cw.Emit(Op.Call); } }
//Finds a function from a Enum class - either enumFrom, enumFromTo or succ. private ScopeVar GetFunction(string name, ElaRange range) { var sv = GetGlobalVariable(name, GetFlags.NoError, range.Line, range.Column); var args = name == "enumFrom" ? 2 : name == "enumFromTo" ? 3 : 1; //Do some validation to ensure that a found function at least "looks like" //a correct one - e.g. is a class member and have a correct number of arguments. if (!options.IgnoreUndefined && (sv.IsEmpty() || (sv.Flags & ElaVariableFlags.ClassFun) != ElaVariableFlags.ClassFun || args != sv.Data)) AddError( name == "enumFrom" ? ElaCompilerError.FromEnumNotFound : name == "enumFromTo" ? ElaCompilerError.FromEnumToNotFound : ElaCompilerError.SuccNotFound, range); return sv; }
void RangeExpr(ElaExpression first, ElaExpression sec, out ElaRange rng) { rng = new ElaRange(t) { First = first, Second = sec }; var cexp = default(ElaExpression); Expect(58); if (StartOf(3)) { Expr(out cexp); rng.Last = cexp; } }
void ParamList(out List<ElaExpression> list, out ElaComprehension comp, out ElaRange rng ) { var exp = default(ElaExpression); list = null; comp = null; rng = null; Expr(out exp); if (la.kind == 26 || la.kind == 56 || la.kind == 58) { if (la.kind == 26) { ComprehensionExpr(exp, out comp); } else if (la.kind == 58) { RangeExpr(exp, null, out rng); } else { var oexp = exp; Get(); Expr(out exp); if (la.kind == 58) { RangeExpr(oexp, exp, out rng); } else if (la.kind == 22 || la.kind == 56) { list = new List<ElaExpression>(); list.Add(oexp); list.Add(exp); while (la.kind == 56) { Get(); Expr(out exp); list.Add(exp); } } else SynErr(76); } } if (list == null && comp == null && rng == null && exp != null) { list = new List<ElaExpression>(); list.Add(exp); } }