private void Build(DYield node, Hints hints, CompilerContext ctx) { Build(node.Expression, hints.Append(Push), ctx); AddLinePragma(node); cw.Yield(); PushIf(hints); }
private void AddHint(object obj) { if (!Guard.IsNullOrEmpty(CurrentHint)) { Hints.Add(CurrentHint.Trim()); } }
private void Build(DWhile node, Hints hints, CompilerContext ctx) { ctx = new CompilerContext(ctx) { BlockSkip = cw.DefineLabel(), BlockExit = cw.DefineLabel(), BlockBreakExit = cw.DefineLabel() }; var iter = cw.DefineLabel(); hints = hints.Remove(Last); var nh = hints.Has(Push) ? hints.Remove(Push).Append(ExpectPush) : hints; if (node.DoWhile) { Build(node.Body, nh, ctx); } cw.MarkLabel(iter); Build(node.Condition, hints.Append(Push), ctx); cw.Brfalse(ctx.BlockExit); Build(node.Body, nh, ctx); cw.MarkLabel(ctx.BlockSkip); cw.Br(iter); cw.MarkLabel(ctx.BlockExit); PushIf(hints); AddLinePragma(node); cw.MarkLabel(ctx.BlockBreakExit); cw.Nop(); }
private void BuildRangeElement(DPattern node, Hints hints) { switch (node.NodeType) { case NodeType.IntegerPattern: cw.Push(((DIntegerPattern)node).Value); break; case NodeType.FloatPattern: cw.Push(((DFloatPattern)node).Value); break; case NodeType.BooleanPattern: cw.Push(((DBooleanPattern)node).Value); break; case NodeType.CharPattern: cw.Push(((DCharPattern)node).Value); break; case NodeType.StringPattern: cw.Push(((DStringPattern)node).Value.Value); break; case NodeType.NilPattern: cw.PushNil(); break; default: AddError(CompilerError.PatternNotSupported, node.Location, node); break; } }
private void PreinitCtor(DCtorPattern node, Hints hints) { if (node.Arguments != null && node.Arguments.Count > 0) { PreinitSequence(node.Arguments, hints); } }
private void BuildName(DNamePattern node, Hints hints, CompilerContext ctx) { var err = GetTypeHandle(null, node.Name, out var handle, out var std); if (err == CompilerError.None) { cw.TypeCheck(new TypeHandle(handle, std)); } else { ScopeVar sv = default; var found = hints.Has(Rebind) ? TryGetVariable(node.Name, out sv) : hints.Has(OpenMatch) ? false : TryGetLocalVariable(node.Name, out sv); var sva = sv.Address; if (!found) { sva = AddVariable(node.Name, node, hints.Has(Const) ? VarFlags.Const : VarFlags.None); } else if ((sv.Data & VarFlags.Const) == VarFlags.Const) { AddError(CompilerError.UnableAssignConstant, node.Location, node.Name); } cw.PopVar(sva); cw.Push(true); } }
private void BuildRange(DRangePattern node, Hints hints, CompilerContext ctx) { var skip = cw.DefineLabel(); var exit = cw.DefineLabel(); cw.Dup(); //2 objs cw.HasMember(GetMemberNameId(Builtins.Lt)); cw.Brfalse(skip); //1 left cw.Dup(); //2 objs cw.HasMember(GetMemberNameId(Builtins.Gt)); cw.Brfalse(skip); //1 left cw.Dup(); //2 objs BuildRangeElement(node.From, hints); cw.GtEq(); cw.Brfalse(skip); //1 left cw.Dup(); //2 objs BuildRangeElement(node.To, hints); cw.LtEq(); cw.Brfalse(skip); //1 left cw.Push(true); cw.Pop(); //0 left cw.Br(exit); cw.MarkLabel(skip); cw.Pop(); //0 left cw.Push(false); cw.MarkLabel(exit); cw.Nop(); }
private void BuildAs(DAsPattern node, Hints hints, CompilerContext ctx) { cw.Dup(); BuildPattern(node.Pattern, hints, ctx); var bad = cw.DefineLabel(); var ok = cw.DefineLabel(); cw.Brfalse(bad); var sva = -1; if (!TryGetLocalVariable(node.Name, out var sv)) { sva = AddVariable(node.Name, node, VarFlags.None); } else { sva = sv.Address; } cw.PopVar(sva); cw.Push(true); cw.Br(ok); cw.MarkLabel(bad); cw.Pop(); cw.Push(false); cw.MarkLabel(ok); cw.Nop(); }
private void BuildMethodCheck(DMethodCheckPattern node, Hints hints, CompilerContext ctx) { AddLinePragma(node); var nameId = GetMemberNameId(node.Name); cw.HasMember(nameId); }
private void BuildCtor(DCtorPattern node, Hints hints, CompilerContext ctx) { var bad = cw.DefineLabel(); var ok = cw.DefineLabel(); cw.Dup(); var nameId = GetMemberNameId(node.Constructor); cw.CtorCheck(nameId); cw.Brfalse(bad); if (node.Arguments == null || node.Arguments.Count == 0) { cw.Pop(); cw.Push(true); } else { BuildSequence(node, node.Arguments, hints, ctx); } cw.Br(ok); cw.MarkLabel(bad); AddLinePragma(node); cw.Pop(); cw.Push(false); cw.MarkLabel(ok); }
//Compile conditional if-then-else operator private void CompileConditionalOperator(ElaCondition s, LabelMap map, Hints hints) { AddLinePragma(s); CompileExpression(s.Condition, map, Hints.Scope, s); var falseLab = cw.DefineLabel(); cw.Emit(Op.Brfalse, falseLab); //Both the True and False parts may be the tail expressions //Also this whole operator can be used as a statement. Or can be compiled //in a situation when some of the referenced names are not initialized (Lazy) var left = (hints & Hints.Left) == Hints.Left ? Hints.Left : Hints.None; var tail = (hints & Hints.Tail) == Hints.Tail ? Hints.Tail : Hints.None; if (s.True != null) CompileExpression(s.True, map, left | tail | Hints.Scope, s); if (s.False != null) { var skipLabel = cw.DefineLabel(); cw.Emit(Op.Br, skipLabel); cw.MarkLabel(falseLab); CompileExpression(s.False, map, left | tail | Hints.Scope, s); cw.MarkLabel(skipLabel); cw.Emit(Op.Nop); } else { AddError(ElaCompilerError.ElseMissing, s.True); AddHint(ElaCompilerHint.AddElse, s.True); } }
//Used to compile a 'try' expression. private void CompileTryExpression(ElaTry n, LabelMap map, Hints hints) { var catchLab = cw.DefineLabel(); var exitLab = cw.DefineLabel(); //Generate a start of a 'try' section AddLinePragma(n); cw.Emit(Op.Start, catchLab); CompileExpression(n.Expression, map, Hints.None, n); //Leaving 'try' section cw.Emit(Op.Leave); cw.Emit(Op.Br, exitLab); cw.MarkLabel(catchLab); cw.Emit(Op.Leave); //Throw hint is to tell match compiler to generate a different typeId if //all pattern fail - to rethrow an original error instead of generating a //new MatchFailed error. CompileSimpleMatch(n.Entries.Equations, map, hints | Hints.Throw, null); cw.MarkLabel(exitLab); cw.Emit(Op.Nop); if ((hints & Hints.Left) == Hints.Left) { AddValueNotUsed(map, n); } }
private void Build(DTupleLiteral node, Hints hints, CompilerContext ctx) { for (var i = 0; i < node.Elements.Count; i++) { var el = node.Elements[i]; string name; if (el.NodeType == NodeType.Label) { var label = (DLabelLiteral)el; Build(label.Expression, hints.Append(Push), ctx); cw.Tag(label.Label); } else { Build(el, hints.Append(Push), ctx); if ((name = el.GetName()) != null) { cw.Tag(name); } } } AddLinePragma(node); cw.NewTuple(node.Elements.Count); PopIf(hints); }
/** * Creates a new QuestManager. Therefore the HintsManager (attached to the HintDisplay) * is needed. */ private QuestManager() { questInformation = new Dictionary <Quest, QuestInfo>(); questInformation.Add(Quest.BrokenFuse, new QuestInfo()); questInformation.Add(Quest.ElectricCircuit, new QuestInfo()); questInformation.Add(Quest.ComputerPassword, new QuestInfo()); questInformation.Add(Quest.Voltage, new QuestInfo()); questInformation.Add(Quest.Document, new QuestInfo()); questInformation.Add(Quest.None, new QuestInfo()); questsSolved = new Dictionary <Quest, bool>(); questsSolved.Add(Quest.BrokenFuse, false); questsSolved.Add(Quest.ElectricCircuit, false); questsSolved.Add(Quest.ComputerPassword, false); questsSolved.Add(Quest.Voltage, false); questsSolved.Add(Quest.Document, false); questsSolved.Add(Quest.None, false); hints = Hints.getHints(); if (StoreGamificationData) { CreateGame(); // Create Game in Gamification Database } }
private void Build(DAssignment node, Hints hints, CompilerContext ctx) { CheckTarget(node.Target); if (node.AutoAssign == BinaryOperator.Coalesce) { BuildCoalesce(node, hints, ctx); return; } if (node.AutoAssign != null) { Build(node.Target, hints.Append(Push), ctx); } Build(node.Value, hints.Append(Push), ctx); if (node.AutoAssign != null) { EmitBinaryOp(node.AutoAssign.Value); } Build(node.Target, hints.Append(Pop), ctx); if (hints.Has(Push)) { cw.PushNil(); } }
private bool BuildSetter(DAssignment node, Hints hints, CompilerContext ctx) { var acc = (DAccess)node.Target; EmitSetter(acc.Target, node.Value, acc.Name, hints, ctx); return(true); }
private void Build(DIteratorLiteral node, Hints hints, CompilerContext ctx) { if (node.YieldBlock.Elements.Count is 1 && node.YieldBlock.Elements[0].NodeType == NodeType.Range) { Build(node.YieldBlock.Elements[0], hints.Append(Push), ctx); PopIf(hints); }
private void GenerateConstructor(DFunctionDeclaration func, Hints hints, CompilerContext ctx) { if (func.Parameters.Count == 0) { AddLinePragma(func); cw.PushNil(); } else if (func.Parameters.Count == 1) { var p = func.Parameters[0]; var a = GetVariable(p.Name, p); AddLinePragma(func); cw.PushVar(a); cw.Tag(p.Name); } else { for (var i = 0; i < func.Parameters.Count; i++) { var p = func.Parameters[i]; var a = GetVariable(p.Name, p); cw.PushVar(a); cw.Tag(p.Name); } AddLinePragma(func); cw.NewTuple(func.Parameters.Count); } TryGetLocalType(func.TypeName.Local, out var ti); cw.Aux(GetMemberNameId(func.Name)); cw.NewType(ti.TypeId); }
public void Example3() { var objects = new[] { new { MachineName = "ctxtest01", Ip = "10.0.0.10", Ports = new[] { 80, 8080, 9090 }, Comments = "" }, new { MachineName = "ctxtest02", Ip = "10.0.0.11", Ports = new[] { 5432 }, Comments = @"This bad boy hosts our database and a couple of internal jobs." } }; var hints = new Hints { MaxTableWidth = 80 }; var formatter = new TableFormatter(hints); var text = formatter.FormatObjects(objects); Console.WriteLine(text); /* * * ==================================================================================== | MachineName | Ip | Ports | Comments | | ==================================================================================== | ctxtest01 | 10.0.0.10 | 80 | | | | | 8080 | | | | | 9090 | | | ==================================================================================== | ctxtest02 | 10.0.0.11 | 5432 | This bad boy hosts our database and a couple | | | | | of internal jobs. | | ==================================================================================== | */ }
public Controller() { _graphics = new ConsoleGraphics(); _userActionListener = new UserActionListener(); _modularWindow = new ModularWindow(_graphics); _fileSystemService = new FileSystemService(); _tabs = new List <Tab>() { new Tab(Settings.LeftWindowCoordinateX, Settings.WindowCoordinateY, _userActionListener, _fileSystemService) { IsActive = true }, new Tab(Settings.RigthWindowCoordinateX, Settings.WindowCoordinateY, _userActionListener, _fileSystemService) }; _systemItemView = new SystemItemView(_graphics); _tabView = new TabView(_tabs, _graphics, _systemItemView); _hints = new Hints(_graphics); _userActionListener.TabSwitching += SelectNextTab; _userActionListener.PropertyRequest += GetProperty; _userActionListener.FileServiceOperation += OperationEventHandler; _userActionListener.CompletionOfWork += () => Exit = true; }
//Compiles Ela 'is' expression. private void CompileTypeCheck(ElaTypeCheck n, LabelMap map, Hints hints) { var failLab = cw.DefineLabel(); var endLab = cw.DefineLabel(); var sysVar = AddVariable(); CompileExpression(n.Expression, map, Hints.None, n); PopVar(sysVar); //Here we are checking all classes specified in a pattern. We have to loop //through all classes and generate a check instruction (Traitch) for each. for (var i = 0; i < n.Traits.Count; i++) { var t = n.Traits[i]; PushVar(sysVar); CheckTypeOrClass(t.Prefix, t.Name, failLab, n); } cw.Emit(Op.PushI1_1); cw.Emit(Op.Br, endLab); cw.MarkLabel(failLab); cw.Emit(Op.PushI1_0); cw.MarkLabel(endLab); cw.Emit(Op.Nop); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(n); }
//לאחר קבלת רמז הוספת המילה לטבלת Hints כולל שם מקבל הרמז public int PostHintToDB(Hints hint) { SqlConnection con; SqlCommand cmd; try { con = Connect("DBConnectionString"); } catch (Exception ex) { // write to log throw ex; } try { String cStr = BuildInsertHintCommand(hint); cmd = CreateCommand(cStr, con); int numEffected = cmd.ExecuteNonQuery(); return(numEffected); } catch (Exception ex) { return(0); throw (ex); } finally { if (con != null) { con.Close(); } } }
private void CompileLazyList(ElaGenerator s, LabelMap map, Hints hints) { var fun = CompileRecursiveFor(s, map, hints, -1, -1); CompileExpression(s.Target, map, Hints.None, s); PushVar(fun); cw.Emit(Op.Call); }
private bool BuildAssignment(DAssignment node, Hints hints, CompilerContext ctx) { Build(node.Value, hints.Append(Push), ctx); Build(node.Target, hints.Remove(Push).Append(Pop), ctx); PushIf(hints); return(true); }
private void StartButton_Click(object sender, RoutedEventArgs e) { Random rand = new Random(); int number = rand.Next(0, 1000); int guess = 0; Hints.Text = guess.ToString(); while (guess != number) { if (guess < number) { Hints.AppendText($"Your guess is too low, please try agian."); } else if (guess > number) { Hints.AppendText($"Your guess is too high, please try agian."); } else if (guess == number) { MessageBox.Show($"Thats correct! {guess} is what the computer picked."); break; } } }
private static void InitHintsOffsets() { // Нужно растянуть подсказки так, чтобы за час, или даже четыре, их было нереально докачать. // Соответственно, последняя подсказка должна быть дальше, чем: // DownloadSpeedBytesPerSecond * 3600 * 3 (bytes) // В соответствии с задумкой располагать данные через увеличивающиеся промежутки трэша, то есть: +-+--+----+--------+... // получаем, что нужно найти степень двойки >= чем наш последний оффсет: const long minimumLastOffset = DownloadSpeedBytesPerSecond * 3600 * 5; log.Debug(string.Format("minimumLastOffset: {0}", minimumLastOffset)); var numberOfOffsets = (int)Math.Ceiling(Math.Log(minimumLastOffset) / Math.Log(2)); var spacing = Encoding.UTF8.GetBytes(FirstHints[0]).Length; var rand = new Random(); HintOffsets.Add(0); for (var i = 0; i < numberOfOffsets - 1; i++) { var nextOffset = (long)(spacing * 2 * (Math.Pow(2, i) + 1)); HintOffsets.Add(nextOffset); var nextHint = i < 4 ? FirstHints[i] : HintsPool[rand.Next(HintsPool.Length)]; Hints.Add(string.Format(nextHint, nextOffset)); log.Info(i + ": " + Hints[i]); } Hints.Add(Flag); TotalFileLength = HintOffsets[numberOfOffsets - 1] + Encoding.UTF8.GetBytes(Hints[numberOfOffsets - 1]).Length; }
private void Build(DTypeDeclaration node, Hints hints, CompilerContext ctx) { var typeId = unit.Types.Count; var unitId = unit.UnitIds.Count - 1; var ti = new TypeInfo(typeId, new UnitInfo(unitId, unit)); if (types.ContainsKey(node.Name)) { types.Remove(node.Name); AddError(CompilerError.TypeAlreadyDeclared, node.Location, node.Name); } types.Add(node.Name, ti); var td = new TypeDescriptor(node.Name, typeId, node.HasConstructors); unit.Types.Add(td); unit.TypeMap.Add(node.Name, td); if (node.HasConstructors) { var nh = hints.Remove(Push).Remove(ExpectPush); foreach (var c in node.Constructors) { Build(c, nh, ctx); } } PushIf(hints); }
private void Build(DArrayLiteral node, Hints hints, CompilerContext ctx) { if (node.Elements.Count == 1 && node.Elements[0].NodeType == NodeType.Range) { Build(node.Elements[0], hints.Append(Push), ctx); cw.GetMember(GetMemberNameId("toArray")); cw.FunPrep(0); AddLinePragma(node); cw.FunCall(0); } else { cw.Type(new TypeHandle(DyType.Array, true)); cw.GetMember(GetMemberNameId(DyTypeNames.Array)); cw.FunPrep(node.Elements.Count); for (var i = 0; i < node.Elements.Count; i++) { Build(node.Elements[i], hints.Append(Push), ctx); cw.FunArgIx(i); } AddLinePragma(node); cw.FunCall(node.Elements.Count); } PopIf(hints); }
//Compiles Ela 'is' expression. private void CompileTypeCheck(ElaTypeCheck n, LabelMap map, Hints hints) { var failLab = cw.DefineLabel(); var endLab = cw.DefineLabel(); var sysVar = AddVariable(); CompileExpression(n.Expression, map, Hints.None, n); PopVar(sysVar); //Here we are checking all classes specified in a pattern. We have to loop //through all classes and generate a check instruction (Traitch) for each. for (var i = 0; i < n.Traits.Count; i++) { var t = n.Traits[i]; PushVar(sysVar); CheckTypeOrClass(t.Prefix, t.Name, failLab, n); } cw.Emit(Op.PushI1_1); cw.Emit(Op.Br, endLab); cw.MarkLabel(failLab); cw.Emit(Op.PushI1_0); cw.MarkLabel(endLab); cw.Emit(Op.Nop); if ((hints & Hints.Left) == Hints.Left) { AddValueNotUsed(map, n); } }
private void Build(DIf node, Hints hints, CompilerContext ctx) { var falseLabel = cw.DefineLabel(); var skipLabel = cw.DefineLabel(); StartScope(false, node.Location); Build(node.Condition, hints.Remove(Last).Append(Push), ctx); AddLinePragma(node); cw.Brfalse(falseLabel); Build(node.True, hints, ctx); AddLinePragma(node); cw.Br(skipLabel); cw.MarkLabel(falseLabel); if (node.False != null) { Build(node.False, hints, ctx); } else { PushIf(hints); } cw.MarkLabel(skipLabel); cw.Nop(); EndScope(); }
public void Add(Field field) { if (field == null || FieldTrackingIds.Contains(field.TrackingId)) { return; } _passwordFields = _usernameFields = null; FieldTrackingIds.Add(field.TrackingId); Fields.Add(field); AutofillIds.Add(field.AutofillId); if (field.Hints != null) { foreach (var hint in field.Hints) { Hints.Add(hint); if (field.Focused) { FocusedHints.Add(hint); } if (!HintToFieldsMap.ContainsKey(hint)) { HintToFieldsMap.Add(hint, new List <Field>()); } HintToFieldsMap[hint].Add(field); } } }
private void Build(DAs node, Hints hints, CompilerContext ctx) { PushTypeInfo(ctx, node.TypeName, node.Location); Build(node.Expression, hints.Append(Push), ctx); AddLinePragma(node); cw.Cast(); PopIf(hints); }
//Compiles xs literal private ExprData CompileTuple(ElaTupleLiteral v, LabelMap map, Hints hints) { CompileTupleParameters(v, v.Parameters, map); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(v); return new ExprData(DataKind.VarType, (Int32)ElaTypeCode.Tuple); }
private void CompileGenerator(ElaGenerator s, LabelMap map, Hints hints) { StartScope(false, s.Line, s.Column); var iter = cw.DefineLabel(); var breakExit = cw.DefineLabel(); var newMap = new LabelMap(map); var addr = -1; if (s.Pattern.Type == ElaNodeType.NameReference) addr = AddVariable(s.Pattern.GetName(), s.Pattern, ElaVariableFlags.None, -1); else addr = AddVariable(); var serv = AddVariable(); CompileExpression(s.Target, map, Hints.None, s); cw.Emit(Op.Dup); PopVar(serv); cw.Emit(Op.Isnil); cw.Emit(Op.Brtrue, breakExit); cw.MarkLabel(iter); PushVar(serv); cw.Emit(Op.Isnil); cw.Emit(Op.Brtrue, breakExit); PushVar(serv); cw.Emit(Op.Head); PopVar(addr); PushVar(serv); cw.Emit(Op.Tail); PopVar(0 | ((addr >> 8) + 1) << 8); if (s.Pattern.Type != ElaNodeType.NameReference) CompilePattern(addr, s.Pattern, iter, false /*allowBang*/, false /*forceStrict*/); if (s.Guard != null) { CompileExpression(s.Guard, map, Hints.None, s); cw.Emit(Op.Brfalse, iter); } if (s.Body != null) { CompileExpression(s.Body, newMap, Hints.Scope, s); if (s.Body.Type != ElaNodeType.Generator) cw.Emit(Op.Cons); } cw.Emit(Op.Br, iter); cw.MarkLabel(breakExit); EndScope(); cw.Emit(Op.Nop); }
public Version(XmlNode node) { if (node.Attributes != null && node.Attributes["value"] != null) _value = node.Attributes["value"].Value; else _value = Unspecified; _hints = Hints.Parse(node["hints"]); _names = ParseNames(node["names"]); }
//Compiles any given expression as lazy, can be used to automatically generate thunks //as well as to compile an explicit lazy literal. private ExprData CompileLazyExpression(ElaExpression exp, LabelMap map, Hints hints) { Label funSkipLabel; int address; LabelMap newMap; CompileFunctionProlog(null, 1, exp.Line, exp.Column, out funSkipLabel, out address, out newMap); var ed = CompileExpression(exp, newMap, Hints.Scope | Hints.FunBody, null); CompileFunctionEpilog(null, 1, address, funSkipLabel); cw.Emit(Op.Newlazy); return ed; }
//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); } }
//Compiles a primitive literal value private ExprData CompilePrimitive(ElaPrimitive p, LabelMap map, Hints hints) { AddLinePragma(p); PushPrimitive(p.Value); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(p); if (p.Parens && p.Value.IsNegative()) { AddWarning(ElaCompilerWarning.SectionAmbiguity, p, p.Value.ToString()); AddHint(ElaCompilerHint.AddSpaceSection, p, p.Value.ToString().TrimStart('-')); } return new ExprData(DataKind.VarType, (Int32)p.Value.LiteralType); }
private ExprData CompileLazy(ElaLazyLiteral exp, LabelMap map, Hints hints) { var ed = default(ExprData); //Try to optimize lazy section for a case //when a function application is marked as lazy if (!TryOptimizeLazy(exp, map, hints)) { //Regular lazy section compilation //Create a closure around section ed = CompileLazyExpression(exp.Expression, map, hints); } if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(exp); return ed; }
//Compiles list literal private ExprData CompileList(ElaListLiteral p, LabelMap map, Hints hints) { var len = p.Values.Count; AddLinePragma(p); cw.Emit(Op.Newlist); //If len is 0 than we have an empty (nil) list which is created by Newlist. for (var i = 0; i < len; i++) { CompileExpression(p.Values[p.Values.Count - i - 1], map, Hints.None, p); cw.Emit(Op.Cons); } if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(p); return new ExprData(DataKind.VarType, (Int32)ElaTypeCode.List); }
//Compiles record literal private ExprData CompileRecord(ElaRecordLiteral p, LabelMap map, Hints hints) { AddLinePragma(p); cw.Emit(Op.Newrec, p.Fields.Count); for (var i = 0; i < p.Fields.Count; i++) { var f = p.Fields[i]; CompileExpression(f.FieldValue, map, Hints.None, f); cw.Emit(Op.Pushstr, AddString(f.FieldName)); cw.Emit(Op.Reccons, i); } if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(p); return new ExprData(DataKind.VarType, (Int32)ElaTypeCode.Record); }
//Compiles logical OR operator in a lazy manner. private void CompileLogicalOr(ElaExpression parent, ElaExpression left, ElaExpression right, LabelMap map, Hints hints) { //Logical OR is executed in a lazy manner var exitLab = default(Label); var termLab = default(Label); var ut = hints; if ((ut & Hints.Left) == Hints.Left) ut ^= Hints.Left; if ((ut & Hints.Tail) == Hints.Tail) ut ^= Hints.Tail; CompileExpression(left, map, ut, parent); termLab = cw.DefineLabel(); exitLab = cw.DefineLabel(); cw.Emit(Op.Brtrue, termLab); CompileExpression(right, map, ut, parent); cw.Emit(Op.Br, exitLab); cw.MarkLabel(termLab); cw.Emit(Op.PushI1_1); cw.MarkLabel(exitLab); cw.Emit(Op.Nop); }
private ExprData CompileExpression(ElaExpression exp, LabelMap map, Hints hints, ElaExpression parent) { var exprData = ExprData.Empty; switch (exp.Type) { case ElaNodeType.As: case ElaNodeType.Equation: AddError(ElaCompilerError.InvalidExpression, exp, FormatNode(exp)); break; case ElaNodeType.Context: { var v = (ElaContext)exp; if (!v.Context.Parens && v.Context.Type == ElaNodeType.NameReference) { var nr = (ElaNameReference)v.Context; if (nr.Uppercase) EmitSpecName(null, "$$" + nr.Name, nr, ElaCompilerError.UndefinedType); else { CompileExpression(v.Context, map, Hints.None, v); cw.Emit(Op.Api, 5); //TypeCode } } else if (!v.Context.Parens && v.Context.Type == ElaNodeType.FieldReference) { var fr = (ElaFieldReference)v.Context; if (Char.IsUpper(fr.FieldName[0]) && fr.TargetObject.Type == ElaNodeType.NameReference) EmitSpecName(fr.TargetObject.GetName(), "$$" + fr.FieldName, fr, ElaCompilerError.UndefinedType); else { CompileExpression(v.Context, map, Hints.None, v); cw.Emit(Op.Api, 5); //TypeCode } } else { CompileExpression(v.Context, map, Hints.None, v); cw.Emit(Op.Force); cw.Emit(Op.Api, 5); //TypeCode } AddLinePragma(v); var a = AddVariable(); cw.Emit(Op.Dup); cw.Emit(Op.Ctx); PopVar(a); var newMap = map.Clone(a); CompileExpression(v.Expression, newMap, hints, v); } break; case ElaNodeType.Builtin: { var v = (ElaBuiltin)exp; CompileBuiltin(v.Kind, v, map, map.BindingName); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(exp); } break; case ElaNodeType.Generator: { CompileGenerator((ElaGenerator)exp, map, hints); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(exp); } break; case ElaNodeType.TypeCheck: { var n = (ElaTypeCheck)exp; CompileTypeCheck(n, map, hints); } break; case ElaNodeType.Range: { var r = (ElaRange)exp; CompileRange(exp, r, map, hints); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(r); } break; case ElaNodeType.LazyLiteral: { var v = (ElaLazyLiteral)exp; CompileLazy(v, map, hints); } break; case ElaNodeType.LetBinding: { var v = (ElaLetBinding)exp; StartScope(false, v.Line, v.Column); CompileEquationSet(v.Equations, map); CompileExpression(v.Expression, map, hints, v); EndScope(); } break; case ElaNodeType.Try: { var s = (ElaTry)exp; CompileTryExpression(s, map, hints); } break; case ElaNodeType.Comprehension: { var c = (ElaComprehension)exp; AddLinePragma(c); if (c.Lazy) CompileLazyList(c.Generator, map, hints); else { cw.Emit(Op.Newlist); CompileGenerator(c.Generator, map, Hints.None); AddLinePragma(c); cw.Emit(Op.Genfin); } if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(c); } break; case ElaNodeType.Match: { var n = (ElaMatch)exp; CompileMatchExpression(n, map, hints); } break; case ElaNodeType.Lambda: { var f = (ElaLambda)exp; var pc = CompileLambda(f); exprData = new ExprData(DataKind.FunParams, pc); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(exp); } break; case ElaNodeType.Condition: { var s = (ElaCondition)exp; CompileConditionalOperator(s, map, hints); } break; case ElaNodeType.Raise: { var s = (ElaRaise)exp; CompileExpression(s.Expression, map, Hints.None, s); AddLinePragma(s); cw.Emit(Op.Throw); } break; case ElaNodeType.Primitive: { var p = (ElaPrimitive)exp; exprData = CompilePrimitive(p, map, hints); } break; case ElaNodeType.RecordLiteral: { var p = (ElaRecordLiteral)exp; exprData = CompileRecord(p, map, hints); } break; case ElaNodeType.FieldReference: { var p = (ElaFieldReference)exp; //Here we check if a field reference is actually an external name //prefixed by a module alias. This call is not neccessary (modules //are first class) but is used as optimization. if (!TryOptimizeFieldReference(p)) { CompileExpression(p.TargetObject, map, Hints.None, p); cw.Emit(Op.Pushstr, AddString(p.FieldName)); AddLinePragma(p); cw.Emit(Op.Pushfld); } if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(exp); } break; case ElaNodeType.ListLiteral: { var p = (ElaListLiteral)exp; exprData = CompileList(p, map, hints); } break; case ElaNodeType.NameReference: { var v = (ElaNameReference)exp; AddLinePragma(v); var scopeVar = GetVariable(v.Name, v.Line, v.Column); //Bang patterns are only allowed in functions and constructors if (v.Bang) { AddError(ElaCompilerError.BangPatternNotValid, exp, FormatNode(exp)); AddHint(ElaCompilerHint.BangsOnlyFunctions, exp); } //This a polymorphic constant if ((scopeVar.Flags & ElaVariableFlags.Polyadric) == ElaVariableFlags.Polyadric) { PushVar(scopeVar); if (map.HasContext) PushVar(map.Context.Value); else cw.Emit(Op.Pushunit); cw.Emit(Op.Disp); } else if ((scopeVar.Flags & ElaVariableFlags.Context) == ElaVariableFlags.Context) { //This is context value, not a real variable cw.Emit(Op.Pushunit); cw.Emit(Op.Api, (Int32)Api.CurrentContext); } else PushVar(scopeVar); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(v); //Add some hints if we know how this name is initialized if ((scopeVar.VariableFlags & ElaVariableFlags.Function) == ElaVariableFlags.Function) exprData = new ExprData(DataKind.FunParams, scopeVar.Data); else if ((scopeVar.VariableFlags & ElaVariableFlags.ObjectLiteral) == ElaVariableFlags.ObjectLiteral) exprData = new ExprData(DataKind.VarType, (Int32)ElaVariableFlags.ObjectLiteral); else if ((scopeVar.VariableFlags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin) exprData = new ExprData(DataKind.Builtin, scopeVar.Data); } break; case ElaNodeType.Placeholder: { if ((hints & Hints.Left) != Hints.Left) AddError(ElaCompilerError.PlaceholderNotValid, exp); else { AddLinePragma(exp); cw.Emit(Op.Pop); } } break; case ElaNodeType.Juxtaposition: { var v = (ElaJuxtaposition)exp; CompileFunctionCall(v, map, hints); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(v); } break; case ElaNodeType.UnitLiteral: if ((hints & Hints.Left) != Hints.Left) cw.Emit(Op.Pushunit); exprData = new ExprData(DataKind.VarType, (Int32)ElaTypeCode.Unit); break; case ElaNodeType.TupleLiteral: { var v = (ElaTupleLiteral)exp; exprData = CompileTuple(v, map, hints); } break; } return exprData; }
//Compiles a sequencing operator private void CompileSeq(ElaExpression parent, ElaExpression left, ElaExpression right, LabelMap map, Hints hints) { var ut = hints; if ((ut & Hints.Left) == Hints.Left) ut ^= Hints.Left; //Sequence operators forces left expression, pops it and yields a value //of a right expression. Evaliation is done in a strict order. CompileExpression(left, map, Hints.None, parent); cw.Emit(Op.Force); cw.Emit(Op.Pop); CompileExpression(right, map, ut, parent); }
//Compiling a regular function call. private ExprData CompileFunctionCall(ElaJuxtaposition v, LabelMap map, Hints hints) { var ed = ExprData.Empty; var bf = default(ElaNameReference); var sv = default(ScopeVar); if (!map.HasContext && TryOptimizeConstructor(v, map)) return ed; if (!map.HasContext && v.Target.Type == ElaNodeType.NameReference) { bf = (ElaNameReference)v.Target; sv = GetVariable(bf.Name, bf.Line, bf.Column); //If the target is one of the built-in application function we need to transform this //to a regular function call, e.g. 'x |> f' is translated into 'f x' by manually creating //an appropriates AST node. This is done to simplify compilation - so that all optimization //of a regular function call would be applied to pipes as well. if ((sv.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin) { var k = (ElaBuiltinKind)sv.Data; if (v.Parameters.Count == 2) { if (k == ElaBuiltinKind.BackwardPipe) { var fc = new ElaJuxtaposition { Target = v.Parameters[0] }; fc.SetLinePragma(v.Line, v.Column); fc.Parameters.Add(v.Parameters[1]); return CompileFunctionCall(fc, map, hints); } else if (k == ElaBuiltinKind.ForwardPipe) { var fc = new ElaJuxtaposition { Target = v.Parameters[1] }; fc.SetLinePragma(v.Line, v.Column); fc.Parameters.Add(v.Parameters[0]); return CompileFunctionCall(fc, map, hints); } else if (k == ElaBuiltinKind.LogicalOr) { CompileLogicalOr(v, v.Parameters[0], v.Parameters[1], map, hints); return ed; } else if (k == ElaBuiltinKind.LogicalAnd) { CompileLogicalAnd(v, v.Parameters[0], v.Parameters[1], map, hints); return ed; } else if (k == ElaBuiltinKind.Seq) { CompileSeq(v, v.Parameters[0], v.Parameters[1], map, hints); return ed; } } } } //We can't apply tail call optimization for the context bound call var tail = (hints & Hints.Tail) == Hints.Tail && !map.HasContext; var len = v.Parameters.Count; //Compile arguments to which a function is applied for (var i = 0; i < len; i++) CompileExpression(v.Parameters[len - i - 1], map, Hints.None, v); //If this a tail call and we effectively call the same function we are currently in, //than do not emit an actual function call, just do a goto. (Tail recursion optimization). if (tail && map.FunctionName != null && map.FunctionName == v.GetName() && map.FunctionParameters == len && map.FunctionScope == GetScope(map.FunctionName) && (sv.Flags & ElaVariableFlags.ClassFun) != ElaVariableFlags.ClassFun) { AddLinePragma(v); cw.Emit(Op.Br, map.FunStart); return ed; } if (bf != null) { if (v.Parameters[0].Type == ElaNodeType.Primitive && bf.Line == v.Parameters[0].Line && bf.Column + bf.Name.Length == v.Parameters[0].Column && ((ElaPrimitive)v.Parameters[0]).Value.IsNegative()) { var par = ((ElaPrimitive)v.Parameters[0]).Value.ToString(); AddWarning(ElaCompilerWarning.NegationAmbiguity, v, bf.Name, par); AddHint(ElaCompilerHint.AddSpaceApplication, v, bf.Name, par, par.TrimStart('-')); } //The target is one of built-in functions and therefore can be inlined for optimization. if ((sv.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin) { var kind = (ElaBuiltinKind)sv.Data; var pars = BuiltinParams(kind); //We inline built-ins only when all arguments are provided //If this is not the case a built-in is compiled into a function in-place //and than called. if (len != pars) { AddLinePragma(bf); CompileBuiltin(kind, v.Target, map, bf.Name); if (v.FlipParameters) cw.Emit(Op.Flip); for (var i = 0; i < len; i++) cw.Emit(Op.Call); } else CompileBuiltinInline(kind, v.Target, map, hints); return ed; } else { //Regular situation, just push a target name AddLinePragma(v.Target); PushVar(sv); if ((sv.VariableFlags & ElaVariableFlags.Function) == ElaVariableFlags.Function) ed = new ExprData(DataKind.FunParams, sv.Data); else if ((sv.VariableFlags & ElaVariableFlags.ObjectLiteral) == ElaVariableFlags.ObjectLiteral) ed = new ExprData(DataKind.VarType, (Int32)ElaVariableFlags.ObjectLiteral); } } else ed = CompileExpression(v.Target, map, Hints.None, v); //Why it comes from AST? Because parser do not save the difference between pre-, post- and infix applications. //However Ela does support left and right sections for operators - and for such cases an additional flag is used //to signal about a section. if (v.FlipParameters) cw.Emit(Op.Flip); //It means that we are trying to call "not a function". Ela is a dynamic language, still it's worth to generate //a warning in such a case. if (ed.Type == DataKind.VarType) AddWarning(ElaCompilerWarning.FunctionInvalidType, v.Target, FormatNode(v.Target)); AddLinePragma(v); for (var i = 0; i < len; i++) { var last = i == v.Parameters.Count - 1; //Use a tail call if this function call is a tail expression and optimizations are enabled. if (last && tail && opt) cw.Emit(Op.Callt); else cw.Emit(Op.Call); } return ed; }
//This methods tries to optimize lazy section. It would only work when a lazy //section if a function application that result in saturation (no partial applications) //allowed. In such a case this method eliminates "double" function call (which would be //the result of a regular compilation logic). If this method fails than regular compilation //logic is used. private bool TryOptimizeLazy(ElaLazyLiteral lazy, LabelMap map, Hints hints) { var body = default(ElaExpression); //Only function application is accepted if ((body = lazy.Expression).Type != ElaNodeType.Juxtaposition) return false; var funCall = (ElaJuxtaposition)body; //If a target is not a variable we can't check what is actually called if (funCall.Target.Type != ElaNodeType.NameReference) return false; var varRef = (ElaNameReference)funCall.Target; var scopeVar = GetVariable(varRef.Name, varRef.Line, varRef.Column); var len = funCall.Parameters.Count; //Only one parameter is allowed if (len > 1) return false; //If a target is not function we can't optimize it if ((scopeVar.VariableFlags & ElaVariableFlags.Function) != ElaVariableFlags.Function) return false; //Only saturation case is optimized if (scopeVar.Data != funCall.Parameters.Count) return false; //We can only optimize a thunk if a last parameter (that will be executed in a strict manner) //is either a primitive value or an already initialized variable. for (var i = 0; i < len; i++) { var p = funCall.Parameters[i]; //Need to check if variable is already initialized. if (p.Type == ElaNodeType.NameReference) { var ssv = GetVariable(p.GetName(), CurrentScope, GetFlags.NoError, 0, 0); if ((ssv.Flags & ElaVariableFlags.NoInit) == ElaVariableFlags.NoInit) return false; } else if (p.Type != ElaNodeType.Primitive) return false; } for (var i = 0; i < len; i++) CompileExpression(funCall.Parameters[len - i - 1], map, Hints.None, funCall); var sl = len - 1; AddLinePragma(varRef); PushVar(scopeVar); //We partially apply function and create a new function for (var i = 0; i < sl; i++) cw.Emit(Op.Call); AddLinePragma(lazy); //LazyCall uses a function provided to create a thunk //and remembers last function arguments as ElaFunction.LastParameter cw.Emit(Op.LazyCall, len); return true; }
//This method can be called directly when a built-in is inlined. private void CompileBuiltinInline(ElaBuiltinKind kind, ElaExpression exp, LabelMap map, Hints hints) { switch (kind) { case ElaBuiltinKind.Seq: cw.Emit(Op.Force); cw.Emit(Op.Pop); break; case ElaBuiltinKind.ForwardPipe: cw.Emit(Op.Swap); cw.Emit(Op.Call); break; case ElaBuiltinKind.BackwardPipe: cw.Emit(Op.Call); break; case ElaBuiltinKind.LogicalOr: { var left = AddVariable(); var right = AddVariable(); PopVar(left); PopVar(right); PushVar(left); var termLab = cw.DefineLabel(); var exitLab = cw.DefineLabel(); cw.Emit(Op.Brtrue, termLab); PushVar(right); cw.Emit(Op.Br, exitLab); cw.MarkLabel(termLab); cw.Emit(Op.PushI1_1); cw.MarkLabel(exitLab); cw.Emit(Op.Nop); } break; case ElaBuiltinKind.LogicalAnd: { var left = AddVariable(); var right = AddVariable(); PopVar(left); PopVar(right); PushVar(left); var termLab = cw.DefineLabel(); var exitLab = cw.DefineLabel(); cw.Emit(Op.Brfalse, termLab); PushVar(right); cw.Emit(Op.Br, exitLab); cw.MarkLabel(termLab); cw.Emit(Op.PushI1_0); cw.MarkLabel(exitLab); cw.Emit(Op.Nop); } break; case ElaBuiltinKind.Head: cw.Emit(Op.Head); break; case ElaBuiltinKind.Tail: cw.Emit(Op.Tail); break; case ElaBuiltinKind.IsNil: cw.Emit(Op.Isnil); break; case ElaBuiltinKind.Negate: cw.Emit(Op.Neg); break; case ElaBuiltinKind.Length: cw.Emit(Op.Len); break; case ElaBuiltinKind.Force: cw.Emit(Op.Force); break; case ElaBuiltinKind.Not: cw.Emit(Op.Not); break; case ElaBuiltinKind.Show: cw.Emit(Op.Show); break; case ElaBuiltinKind.Concat: cw.Emit(Op.Concat); break; case ElaBuiltinKind.Add: cw.Emit(Op.Add); break; case ElaBuiltinKind.Divide: cw.Emit(Op.Div); break; case ElaBuiltinKind.Quot: cw.Emit(Op.Quot); break; case ElaBuiltinKind.Multiply: cw.Emit(Op.Mul); break; case ElaBuiltinKind.Power: cw.Emit(Op.Pow); break; case ElaBuiltinKind.Remainder: cw.Emit(Op.Rem); break; case ElaBuiltinKind.Modulus: cw.Emit(Op.Mod); break; case ElaBuiltinKind.Subtract: cw.Emit(Op.Sub); break; case ElaBuiltinKind.ShiftRight: cw.Emit(Op.Shr); break; case ElaBuiltinKind.ShiftLeft: cw.Emit(Op.Shl); break; case ElaBuiltinKind.Greater: cw.Emit(Op.Cgt); break; case ElaBuiltinKind.Lesser: cw.Emit(Op.Clt); break; case ElaBuiltinKind.Equal: cw.Emit(Op.Ceq); break; case ElaBuiltinKind.NotEqual: cw.Emit(Op.Cneq); break; case ElaBuiltinKind.GreaterEqual: cw.Emit(Op.Cgteq); break; case ElaBuiltinKind.LesserEqual: cw.Emit(Op.Clteq); break; case ElaBuiltinKind.BitwiseAnd: cw.Emit(Op.AndBw); break; case ElaBuiltinKind.BitwiseOr: cw.Emit(Op.OrBw); break; case ElaBuiltinKind.BitwiseXor: cw.Emit(Op.Xor); break; case ElaBuiltinKind.Cons: cw.Emit(Op.Cons); break; case ElaBuiltinKind.BitwiseNot: cw.Emit(Op.NotBw); break; case ElaBuiltinKind.GetValue: cw.Emit(Op.Pushelem); break; case ElaBuiltinKind.GetValueR: cw.Emit(Op.Swap); cw.Emit(Op.Pushelem); break; case ElaBuiltinKind.GetField: cw.Emit(Op.Pushfld); break; case ElaBuiltinKind.HasField: cw.Emit(Op.Hasfld); break; /* Api */ case ElaBuiltinKind.Api1: cw.Emit(Op.Api, 1); break; case ElaBuiltinKind.Api2: cw.Emit(Op.Api, 2); break; case ElaBuiltinKind.Api3: cw.Emit(Op.Api, 3); break; case ElaBuiltinKind.Api4: cw.Emit(Op.Api, 4); break; case ElaBuiltinKind.Api5: cw.Emit(Op.Api, 5); break; case ElaBuiltinKind.Api6: cw.Emit(Op.Api, 6); break; case ElaBuiltinKind.Api7: cw.Emit(Op.Api, 7); break; case ElaBuiltinKind.Api8: cw.Emit(Op.Api, 8); break; case ElaBuiltinKind.Api9: cw.Emit(Op.Api, 9); break; case ElaBuiltinKind.Api10: cw.Emit(Op.Api, 10); break; case ElaBuiltinKind.Api11: cw.Emit(Op.Api, 11); break; case ElaBuiltinKind.Api12: cw.Emit(Op.Api, 12); break; case ElaBuiltinKind.Api13: cw.Emit(Op.Api, 13); break; case ElaBuiltinKind.Api14: cw.Emit(Op.Api, 14); break; case ElaBuiltinKind.Api15: cw.Emit(Op.Api, 15); break; case ElaBuiltinKind.Api16: cw.Emit(Op.Api, 16); break; case ElaBuiltinKind.Api101: cw.Emit(Op.Api2, 101); break; case ElaBuiltinKind.Api102: cw.Emit(Op.Api2, 102); break; case ElaBuiltinKind.Api103: cw.Emit(Op.Api2, 103); break; case ElaBuiltinKind.Api104: cw.Emit(Op.Api2, 104); break; case ElaBuiltinKind.Api105: cw.Emit(Op.Api2, 105); break; case ElaBuiltinKind.Api106: cw.Emit(Op.Api2, 106); break; case ElaBuiltinKind.Api107: cw.Emit(Op.Api2, 107); break; } }
private int CompileRecursiveFor(ElaGenerator s, LabelMap map, Hints hints, int parent, int parentTail) { var funAddr = AddVariable(); StartSection(); StartScope(true, s.Line, s.Column); cw.StartFrame(1); var funSkipLabel = cw.DefineLabel(); cw.Emit(Op.Br, funSkipLabel); var address = cw.Offset; var exitLab = cw.DefineLabel(); var endLab = cw.DefineLabel(); var iterLab = cw.DefineLabel(); var head = AddVariable(); var tail = AddVariable(); var sys = AddVariable(); cw.Emit(Op.Dup); PopVar(sys); cw.Emit(Op.Isnil); cw.Emit(Op.Brtrue, endLab); PushVar(sys); cw.Emit(Op.Head); PopVar(head); PushVar(sys); cw.Emit(Op.Tail); PopVar(tail); if (s.Pattern.Type == ElaNodeType.NameReference) { var addr = AddVariable(s.Pattern.GetName(), s.Pattern, ElaVariableFlags.None, -1); PushVar(head); PopVar(addr); } else CompilePattern(head, s.Pattern, iterLab, false /*allowBang*/, false /*forceStrict*/); if (s.Guard != null) { CompileExpression(s.Guard, map, Hints.None, s); cw.Emit(Op.Brfalse, iterLab); } if (s.Body.Type == ElaNodeType.Generator) { var f = (ElaGenerator)s.Body; var child = CompileRecursiveFor(f, map, hints, funAddr, tail); CompileExpression(f.Target, map, Hints.None, f); PushVar(child); cw.Emit(Op.Call); cw.Emit(Op.Br, exitLab);// } else { PushVar(tail); PushVar(1 | (funAddr >> 8) << 8); cw.Emit(Op.LazyCall); CompileExpression(s.Body, map, Hints.None, s); cw.Emit(Op.Cons); cw.Emit(Op.Br, exitLab); } cw.MarkLabel(iterLab); PushVar(tail); PushVar(1 | (funAddr >> 8) << 8); cw.Emit(Op.Call); cw.Emit(Op.Br, exitLab);// cw.MarkLabel(endLab); if (parent == -1) cw.Emit(Op.Newlist); else { PushVar(1 | (parentTail >> 8) << 8); PushVar(2 | (parent >> 8) << 8); cw.Emit(Op.Call); } cw.MarkLabel(exitLab); cw.Emit(Op.Ret); frame.Layouts.Add(new MemoryLayout(currentCounter, cw.FinishFrame(), address)); EndSection(); EndScope(); cw.MarkLabel(funSkipLabel); cw.Emit(Op.PushI4, 1); cw.Emit(Op.Newfun, frame.Layouts.Count - 1); PopVar(funAddr); return funAddr; }
//Used to compile a 'try' expression. private void CompileTryExpression(ElaTry n, LabelMap map, Hints hints) { var catchLab = cw.DefineLabel(); var exitLab = cw.DefineLabel(); //Generate a start of a 'try' section AddLinePragma(n); cw.Emit(Op.Start, catchLab); CompileExpression(n.Expression, map, Hints.None, n); //Leaving 'try' section cw.Emit(Op.Leave); cw.Emit(Op.Br, exitLab); cw.MarkLabel(catchLab); cw.Emit(Op.Leave); //Throw hint is to tell match compiler to generate a different typeId if //all pattern fail - to rethrow an original error instead of generating a //new MatchFailed error. CompileSimpleMatch(n.Entries.Equations, map, hints | Hints.Throw, null); cw.MarkLabel(exitLab); cw.Emit(Op.Nop); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(n); }
//This method contains main compilation logic for 'match' expressions and for 'try' expressions. //This method only supports a single pattern per entry. //A 'mexp' (matched expression) parameter can be null and is used for additional validation only. private void CompileSimpleMatch(IEnumerable<ElaEquation> bindings, LabelMap map, Hints hints, ElaExpression mexp) { ValidateOverlapSimple(bindings, mexp); var failLab = cw.DefineLabel(); var endLab = cw.DefineLabel(); //We need to remembers the first set of system addresses because we will have //to push them manually for the entries other than first. var firstSys = -1; var first = true; //Loops through all bindings //For the first iteration we assume that all values are already on stack. //For the next iteration we manually push all values. foreach (var b in bindings) { //Each match entry starts a lexical scope StartScope(false, b.Line, b.Column); //For second+ entries we put a label where we would jump if a previous //pattern fails if (!first) { cw.MarkLabel(failLab); failLab = cw.DefineLabel(); } var p = b.Left; var sysVar = -1; //We apply an optimization if a we have a name reference (only for the first iteration). if (p.Type == ElaNodeType.NameReference && first) sysVar = AddVariable(p.GetName(), p, ElaVariableFlags.Parameter, -1); else sysVar = AddVariable(); //Create an unnamed system variable //This is not the first entry, so we have to push values first if (!first) PushVar(firstSys); PopVar(sysVar); //We have to remember addresses calculated in a first iteration //to be able to push them once again in a second iteration. if (first) firstSys = sysVar; CompilePattern(sysVar, p, failLab, false /*allowBang*/, false /*forceStrict*/); first = false; //Compile entry expression if (b.Right == null) AddError(ElaCompilerError.InvalidMatchEntry, b.Left, FormatNode(b)); else CompileExpression(b.Right, map, Hints.None, b); //Close current scope EndScope(); //If everything is OK skip through 'fail' clause cw.Emit(Op.Br, endLab); } //We fall here if all patterns have failed cw.MarkLabel(failLab); //If this hints is set than we generate a match for a 'try' //(exception handling) block. Instead of MatchFailed we need //to rethrow an original exception. Block 'try' always have //just a single expression to match, therefore firstSys[0] is //pretty safe here. if ((hints & Hints.Throw) == Hints.Throw) { PushVar(firstSys); cw.Emit(Op.Rethrow); } else cw.Emit(Op.Failwith, (Int32)ElaRuntimeError.MatchFailed); //Happy path for match cw.MarkLabel(endLab); cw.Emit(Op.Nop); }
//Used to compile a 'match' expression. private void CompileMatchExpression(ElaMatch n, LabelMap map, Hints hints) { CompileExpression(n.Expression, map, Hints.None, n); AddLinePragma(n); CompileSimpleMatch(n.Entries.Equations, map, hints, n.Expression); if ((hints & Hints.Left) == Hints.Left) AddValueNotUsed(n); }
//Pattern match compilation method which is used by functions defined by pattern matching. //Argument patNum contains number of patterns that should be in each. private void CompileFunctionMatch(int patNum, IEnumerable<ElaEquation> bindings, LabelMap map, Hints hints) { ValidateOverlapComplex(bindings); var failLab = cw.DefineLabel(); var endLab = cw.DefineLabel(); //We need to remembers the first set of system addresses because we will have //to push them manually for the entries other than first. var firstSys = new int[patNum]; var first = true; //Loops through all bindings //For the first iteration we assume that all values are already on stack. //For the next iteration we manually push all values. foreach (var b in bindings) { //Each match entry starts a lexical scope StartScope(false, b.Line, b.Column); //This match compilation is used for functions only, //therefore the left-hand should always be a juxtaposition. var fc = (ElaJuxtaposition)b.Left; var len = fc.Parameters.Count; var pars = fc.Parameters; //Entries have different number of patterns, so generate an error and continue //compilation in order to prevent generation of 'redundant' error messages. if (len < patNum) AddError(ElaCompilerError.PatternsTooFew, b.Left, FormatNode(b.Left), patNum, len); else if (len > patNum) AddError(ElaCompilerError.PatternsTooMany, b.Left, FormatNode(b.Left), patNum, len); //For second+ entries we put a label where we would jump if a previous //pattern fails if (!first) { cw.MarkLabel(failLab); failLab = cw.DefineLabel(); } for (var i = 0; i < len; i++) { var p = pars[i]; var sysVar = -1; //We apply an optimization if a we have a name reference (only for the first iteration). if (p.Type == ElaNodeType.NameReference && first) sysVar = AddVariable(p.GetName(), p, ElaVariableFlags.Parameter, -1); else sysVar = AddVariable(); //Create an unnamed system variable //This is not the first entry, so we have to push values first if (!first && firstSys.Length > i) PushVar(firstSys[i]); PopVar(sysVar); //We have to remember addresses calculated in a first iteration //to be able to push them once again in a second iteration. if (first && firstSys.Length > i) firstSys[i] = sysVar; } //Now compile patterns for (var i = 0; i < len; i++) if (firstSys.Length > i && pars.Count > i) CompilePattern(firstSys[i], pars[i], failLab, true /*allowBang*/, false /*forceStrict*/); first = false; //Compile entry expression if (b.Right == null) AddError(ElaCompilerError.InvalidMatchEntry, b.Left, FormatNode(b)); else CompileExpression(b.Right, map, hints, b); //Close current scope EndScope(); //If everything is OK skip through 'fail' clause cw.Emit(Op.Br, endLab); } //We fall here if all patterns have failed cw.MarkLabel(failLab); cw.Emit(Op.Failwith, (Int32)ElaRuntimeError.MatchFailed); //Happy path for match cw.MarkLabel(endLab); cw.Emit(Op.Nop); }