private void Build(DIteratorLiteral node, Hints hints, CompilerContext ctx) { var dec = new DFunctionDeclaration(node.Location) { Body = node.YieldBlock }; Build(dec, hints.Append(Iterator), ctx); }
private void BuildCoalesce(DAssignment node, Hints hints, CompilerContext ctx) { CheckTarget(node.Target); var exitLab = cw.DefineLabel(); Build(node.Target, hints.Remove(Last).Append(Push), ctx); cw.Brtrue(exitLab); Build(node.Value, hints.Append(Push), ctx); Build(node.Target, hints.Append(Pop), ctx); cw.MarkLabel(exitLab); cw.Nop(); if (hints.Has(Push)) { cw.Dup(); } }
private void Build(DMemberCheck node, Hints hints, CompilerContext ctx) { Build(node.Target, hints.Append(Push), ctx); AddLinePragma(node); var nameId = GetMemberNameId(node.Name); cw.HasMember(nameId); PopIf(hints); }
private bool BuildSetterAutoAssign(DAssignment node, Hints hints, CompilerContext ctx) { var acc = (DAccess)node.Target; Build(acc.Target, hints.Remove(Last).Append(Push), ctx); cw.GetMember(Builtins.Setter(acc.Name)); cw.FunPrep(1); EmitGetter(acc.Target, acc.Name, hints, ctx); Build(node.Value, hints.Append(Push), ctx); EmitBinaryOp(node.AutoAssign !.Value); cw.FunArgIx(0); cw.FunCall(1); PopIf(hints); return(true); }
private void Build(DPrivateScope node, Hints hints, CompilerContext ctx) { if (privateScope) { AddError(CompilerError.PrivateScopeNested, node.Location); } if (currentScope != globalScope) { AddError(CompilerError.PrivateScopeOnlyGlobal, node.Location); } privateScope = true; Build(node.Block, hints.Append(NoScope), ctx); privateScope = false; }
private void Build(DYieldBlock node, Hints hints, CompilerContext ctx) { for (var i = 0; i < node.Elements.Count; i++) { var n = node.Elements[i]; var last = i == node.Elements.Count - 1; Build(n, hints.Append(Push), ctx); AddLinePragma(node); cw.Yield(); if (last) { PushIf(hints); } } }
private void Build(DTryCatch node, Hints hints, CompilerContext ctx) { var gotcha = cw.DefineLabel(); cw.Start(gotcha); Build(node.Expression, hints, ctx); AddLinePragma(node); cw.End(); var skip = cw.DefineLabel(); cw.Br(skip); cw.MarkLabel(gotcha); StartScope(ScopeKind.Lexical, node.Catch.Location); //We are inside a catch, we need preserve an exception object for //possible rethrows cw.Dup(); var a = AddVariable(); cw.PopVar(a); ctx.Errors.Push(a); if (node.BindVariable is not null) { AddLinePragma(node.BindVariable); if (node.BindVariable.Value is not "_") { var sv = AddVariable(node.BindVariable.Value, node.Catch.Location, VarFlags.Const); cw.PopVar(sv); } else { cw.Pop(); } } Build(node.Catch, hints.Append(Catch), ctx); ctx.Errors.Pop(); EndScope(); cw.MarkLabel(skip); AddLinePragma(node); cw.Nop(); }
private void Build(DMatch node, Hints hints, CompilerContext ctx) { ValidateMatch(node); StartScope(ScopeKind.Lexical, node.Location); ctx = new(ctx) { MatchExit = cw.DefineLabel() }; var sys = AddVariable(); var push = hints.Append(Push); if (node.Expression != null) { Build(node.Expression, push.Remove(Last), ctx); } cw.PopVar(sys); var sysVar = new ScopeVar(sys); foreach (var e in node.Entries) { BuildEntry(e, sysVar, push, ctx); } //It is some kind of a hack, but Expression can be null //only if this match is inside try/catch if (node.Expression != null) { ThrowError(DyError.MatchFailed); cw.Fail(); } else { cw.PushVar(sysVar); cw.Fail(); } cw.MarkLabel(ctx.MatchExit); cw.Nop(); PopIf(hints); EndScope(); }
private void Build(DReturn node, Hints hints, CompilerContext ctx) { if (ctx.FunctionExit.IsEmpty()) { AddError(CompilerError.ReturnNotAllowed, node.Location); } if (node.Expression != null) { Build(node.Expression, hints.Append(Push), ctx); } else { cw.PushNil(); } AddLinePragma(node); cw.Br(ctx.FunctionExit); }
private bool CanBeOptimized(DBindingBase node, Hints hints, CompilerContext ctx) { if (!options.NoOptimizations && node.Init != null && node.Init.NodeType == NodeType.Tuple && node.Pattern.NodeType == NodeType.TuplePattern && node.Init.GetElementCount() == node.Pattern.GetElementCount()) { var init = (DTupleLiteral)node.Init; var pat = (DTuplePattern)node.Pattern; for (var i = 0; i < pat.Elements.Count; i++) { if (pat.Elements[i].NodeType != NodeType.NamePattern) { return(false); } } for (var i = 0; i < init.Elements.Count; i++) { Build(init.Elements[i], hints.Append(Push), ctx); } for (var i = 0; i < pat.Elements.Count; i++) { var e = pat.Elements[pat.Elements.Count - i - 1]; var addr = node.NodeType == NodeType.Binding ? AddVariable(e.GetName(), e, VarFlags.None) : GetVariableToAssign(e.GetName(), e, false); if (addr == -1 && node.NodeType == NodeType.Rebinding) { addr = AddVariable(e.GetName(), e, VarFlags.None); } cw.PopVar(addr); } return(true); } return(false); }
private void Build(DBreak node, Hints hints, CompilerContext ctx) { if (ctx.BlockExit.IsEmpty()) { AddError(CompilerError.NoEnclosingLoop, node.Location); } if (node.Expression is not null) { Build(node.Expression, hints.Append(Push), ctx); } else { cw.PushNil(); } CallAutosForKind(ScopeKind.Loop); AddLinePragma(node); cw.Br(ctx.BlockBreakExit); }
private void Build(DUnaryOperation node, Hints hints, CompilerContext ctx) { Build(node.Node, hints.Append(Push), ctx); AddLinePragma(node); if (node.Operator == UnaryOperator.Neg) { cw.Neg(); } else if (node.Operator == UnaryOperator.Not) { cw.Not(); } else if (node.Operator == UnaryOperator.BitwiseNot) { cw.BitNot(); } PopIf(hints); }
private void Build(DThrow node, Hints hints, CompilerContext ctx) { if (node.Expression is not null) { Build(node.Expression, hints.Append(Push), ctx); AddLinePragma(node); cw.Fail(); } else { if (!hints.Has(Catch) || ctx.Errors.Count is 0) { AddError(CompilerError.InvalidRethrow, node.Location); } else { cw.PushVar(new ScopeVar(ctx.Errors.Peek())); } AddLinePragma(node); cw.Fail(); } }
private void Build(DBreak node, Hints hints, CompilerContext ctx) { if (ctx.BlockExit.IsEmpty()) { AddError(CompilerError.NoEnclosingLoop, node.Location); } if (node.Expression != null) { Build(node.Expression, hints.Append(Push), ctx); if (!hints.Has(ExpectPush)) { cw.Pop(); } } else if (hints.Has(ExpectPush)) { cw.PushNil(); } AddLinePragma(node); cw.Br(ctx.BlockBreakExit); }
private void Build(DWhile node, Hints hints, CompilerContext ctx) { ctx = new(ctx) { BlockSkip = cw.DefineLabel(), BlockExit = cw.DefineLabel(), BlockBreakExit = cw.DefineLabel() }; StartScope(ScopeKind.Loop, node.Location); var iter = cw.DefineLabel(); hints = hints.Remove(Last); var nh = hints.Remove(Push); 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); cw.PushNil(); AddLinePragma(node); cw.MarkLabel(ctx.BlockBreakExit); PopIf(hints); cw.Nop(); EndScope(); }
private void Build(DFor node, Hints hints, CompilerContext ctx) { ctx = new CompilerContext(ctx) { BlockSkip = cw.DefineLabel(), BlockExit = cw.DefineLabel(), BlockBreakExit = cw.DefineLabel() }; StartScope(false, node.Location); hints = hints.Remove(Last); var inc = -1; if (node.Pattern.NodeType == NodeType.NamePattern && GetTypeHandle(null, node.Pattern.GetName(), out var _, out var _) != CompilerError.None) { inc = AddVariable(node.Pattern.GetName(), node.Pattern, VarFlags.None); } var sys = AddVariable(); var initSkip = cw.DefineLabel(); Build(node.Target, hints.Append(Push), ctx); cw.Briter(initSkip); cw.GetMember(GetMemberNameId(Builtins.Iterator)); cw.FunPrep(0); cw.FunCall(0); cw.MarkLabel(initSkip); cw.PopVar(sys); var iter = cw.DefineLabel(); cw.MarkLabel(iter); cw.PushVar(new ScopeVar(sys)); cw.FunPrep(0); cw.FunCall(0); cw.Brterm(ctx.BlockExit); if (inc > -1) { cw.PopVar(inc); } else { BuildPattern(node.Pattern, hints, ctx); cw.Brfalse(ctx.BlockSkip); } if (node.Guard != null) { Build(node.Guard, hints.Append(Push), ctx); cw.Brfalse(ctx.BlockSkip); } var nh = hints.Has(Push) ? hints.Remove(Push).Append(ExpectPush) : hints.Remove(ExpectPush); Build(node.Body, nh, ctx); cw.MarkLabel(ctx.BlockSkip); cw.Br(iter); cw.MarkLabel(ctx.BlockExit); cw.Pop(); PushIf(hints); AddLinePragma(node); cw.MarkLabel(ctx.BlockBreakExit); cw.Nop(); EndScope(); }
private void Build(DFor node, Hints hints, CompilerContext ctx) { ctx = new(ctx) { BlockSkip = cw.DefineLabel(), BlockExit = cw.DefineLabel(), BlockBreakExit = cw.DefineLabel() }; if (TryOptimizeFor(node, hints, ctx)) { return; } StartScope(ScopeKind.Loop, node.Location); hints = hints.Remove(Last); var inc = false; if (node.Pattern.NodeType == NodeType.NamePattern && !char.IsUpper(((DNamePattern)node.Pattern).Name[0] !)) { inc = true; } var sys = AddVariable(); var initSkip = cw.DefineLabel(); Build(node.Target, hints.Append(Push), ctx); cw.Briter(initSkip); cw.GetMember(Builtins.Iterate); cw.CallNullaryFunction(); cw.MarkLabel(initSkip); cw.GetIter(); cw.PopVar(sys); var iter = cw.DefineLabel(); cw.MarkLabel(iter); cw.PushVar(new ScopeVar(sys)); cw.CallNullaryFunction(); cw.Brterm(ctx.BlockExit); if (inc) { var ai = AddVariable(((DNamePattern)node.Pattern).Name !, node.Pattern.Location, VarFlags.None); cw.PopVar(ai); } else { BuildPattern(node.Pattern, hints, ctx); cw.Brfalse(ctx.BlockSkip); } if (node.Guard != null) { Build(node.Guard, hints.Append(Push), ctx); cw.Brfalse(ctx.BlockSkip); } var nh = hints.Remove(Push); Build(node.Body, nh, ctx); cw.MarkLabel(ctx.BlockSkip); cw.Br(iter); cw.MarkLabel(ctx.BlockExit); cw.Pop(); cw.PushNil(); AddLinePragma(node); cw.MarkLabel(ctx.BlockBreakExit); PopIf(hints); cw.Nop(); EndScope(); }
private void Build(DStringLiteral node, Hints hints, CompilerContext ctx) { if (node.Chunks == null && NoPush(node, hints)) { return; } if (node.Chunks != null) { cw.Type(new TypeHandle(DyType.String, true)); cw.GetMember(GetMemberNameId("concat")); cw.FunPrep(node.Chunks.Count); for (var i = 0; i < node.Chunks.Count; i++) { var c = node.Chunks[i]; if (c.IsCode) { var p = new InternalParser(new Scanner(SourceBuffer.FromString(c.GetContent()))); p.Parse(); if (p.Errors.Count > 0) { foreach (var e in p.Errors) { AddError(CompilerError.CodeIslandInvalid, new Location(node.Location.Line, node.Location.Column + e.Column), e.Message); } } else { if (p.Root.Nodes == null || p.Root.Nodes.Count == 0) { AddError(CompilerError.CodeIslandEmpty, node.Location); } else { corrections.Push(node.Location); Build(p.Root.Nodes[0], hints.Append(Push), ctx); corrections.Pop(); } } } else { cw.Push(c.GetContent()); } cw.FunArgIx(i); } AddLinePragma(node); cw.FunCall(node.Chunks.Count); } else { AddLinePragma(node); cw.Push(node.Value); } PopIf(hints); }
private void Build(DIndexer node, Hints hints, CompilerContext ctx) { var push = hints.Remove(Pop).Append(Push); if (node.Index.NodeType == NodeType.String && node.Index is DStringLiteral str && str.Chunks == null) { if (node.Target.NodeType == NodeType.Name) { var nm = node.Target.GetName(); var sv = GetVariable(nm, node.Target, err: false); if ((sv.Data & VarFlags.Module) == VarFlags.Module && referencedUnits.TryGetValue(nm, out var ru)) { if (ru.Unit.ExportList.TryGetValue(str.Value, out var var)) { if ((var.Data & VarFlags.Private) == VarFlags.Private) { AddError(CompilerError.PrivateNameAccess, node.Location, str.Value); } AddLinePragma(node); cw.PushVar(new ScopeVar(ru.Handle | (var.Address >> 8) << 8, VarFlags.External)); return; } else if (GetTypeHandle(nm, str.Value, out var handle, out var std) == CompilerError.None) { GetMemberNameId(str.Value); AddLinePragma(node); cw.Type(new TypeHandle(handle, std)); return; } } } Build(node.Target, push, ctx); cw.Push(str.Value); if (!hints.Has(Pop)) { cw.Get(); PopIf(hints); } else { cw.Set(); } return; } Build(node.Target, push, ctx); if (node.Index.NodeType == NodeType.Range) { if (hints.Has(Pop)) { AddError(CompilerError.RangeIndexNotSupported, node.Index.Location); } var r = (DRange)node.Index; cw.GetMember(GetMemberNameId("slice")); cw.FunPrep(2); Build(r.From, hints.Append(Push), ctx); cw.FunArgIx(0); Build(r.To, hints.Append(Push), ctx); Build(r.From, hints.Append(Push), ctx); cw.Sub(); cw.FunArgIx(1); AddLinePragma(node); cw.FunCall(2); PopIf(hints); } else { Build(node.Index, push, ctx); AddLinePragma(node); if (!hints.Has(Pop)) { cw.Get(); PopIf(hints); } else { cw.Set(); } } }
private void BuildFunctionBody(int addr, DFunctionDeclaration node, Hints hints, CompilerContext ctx) { var iter = hints.Has(Iterator); var args = CompileFunctionParameters(node.Parameters); var argCount = args.Length; StartFun(node.Name, args, argCount); if (node.IsStatic && !node.IsMemberFunction) { AddError(CompilerError.StaticOnlyMethods, node.Location, node.Name); } var startLabel = cw.DefineLabel(); var funEndLabel = cw.DefineLabel(); //Functions are always compiled "in place": if we find a function while looping //through AST node we compile right away. That is the reason why we need to emit an //additional goto so that we can jump over this function. var funSkipLabel = cw.DefineLabel(); cw.Br(funSkipLabel); ctx = new CompilerContext { FunctionAddress = counters.Count | (addr >> 8) << 8, FunctionStart = startLabel, FunctionExit = funEndLabel, Function = node }; hints = Function | Push; //Start of a physical (and not compiler time) lexical scope for a function StartScope(fun: true, loc: node.Location); StartSection(); AddLinePragma(node); var address = cw.Offset; var variadicIndex = -1; //Initialize function arguments for (var i = 0; i < args.Length; i++) { var arg = args[i]; if (arg.IsVarArg) { variadicIndex = i; } AddVariable(arg.Name, node, data: VarFlags.Argument); } //If this is a member function we add an additional system variable that //would return an instance of an object to which this function is coupled //(same as this in C#) if (node.IsMemberFunction && !node.IsStatic) { var va = AddVariable("this", node, data: VarFlags.Const | VarFlags.This); cw.This(); cw.PopVar(va); } //Start of a function that is used for tail call optimization cw.MarkLabel(startLabel); //This is an autogenerated constructor if (node.IsConstructor) { GenerateConstructor(node, hints, ctx); } else { //Compile function body if (node.IsIterator) { var dec = new DFunctionDeclaration(node.Location) { Name = node.Name, Body = node.Body }; Build(dec, hints.Append(Iterator), ctx); } else { Build(node.Body, hints.Append(Last), ctx); } } //Return from a function. Any function execution should get here, it is not possible //to break early. An early return would actually goto here, where a real return (OpCode.Ret) //is executed. This is a function epilogue. cw.MarkLabel(funEndLabel); //If this is an iterator function push a terminator at the end (and pop a normal value) if (iter) { cw.Pop(); cw.PushNilT(); } cw.Ret(); cw.MarkLabel(funSkipLabel); AddLinePragma(node); //Close all lexical scopes and debugging information var funHandle = unit.Layouts.Count; var ss = EndFun(funHandle); unit.Layouts.Add(new MemoryLayout(currentCounter, ss, address)); EndScope(); EndSection(); //Iterators are a separate type (based on function through) if (iter) { cw.NewIter(funHandle); } else { if (variadicIndex > -1) { cw.Aux(variadicIndex); cw.NewFunV(funHandle); } else { cw.NewFun(funHandle); } } }
private void Build(DBinding node, Hints hints, CompilerContext ctx) { if (CanBeOptimized(node, hints, ctx)) { PushIf(hints); return; } if (node.Init != null) { Build(node.Init, hints.Append(Push), ctx); } else { cw.PushNil(); } if (node.Pattern.NodeType == NodeType.NamePattern) { AddLinePragma(node); var flags = node.Constant ? VarFlags.Const : VarFlags.None; var a = AddVariable(node.Pattern.GetName(), node, flags); cw.PopVar(a); } else { if (node.Init == null) { AddError(CompilerError.BindingPatternNoInit, node.Location); } else { int n; if ((n = node.Pattern.GetElementCount()) == node.Init.GetElementCount() && n != -1 && IsPureBinding(node.Pattern)) { var xs = node.Pattern.ListElements(); var ys = node.Init.ListElements(); var flags = node.Constant ? VarFlags.Const : VarFlags.None; for (var i = 0; i < xs.Count; i++) { var x = xs[i]; var y = ys[i]; Build(y, hints.Append(Push), ctx); AddLinePragma(node); if (x.NodeType != NodeType.WildcardPattern) { var a = AddVariable(x.GetName(), node, flags); cw.PopVar(a); } else { cw.Pop(); } } PushIf(hints); return; } } var nh = hints.Append(OpenMatch); if (node.Constant) { nh = nh.Append(Const); } if (node.Init != null) { CheckPattern(node.Pattern, node.Init.GetElementCount(), node.Pattern.GetElementCount()); } BuildPattern(node.Pattern, nh, ctx); var skip = cw.DefineLabel(); cw.Brtrue(skip); cw.Fail(DyErrorCode.MatchFailed); cw.MarkLabel(skip); cw.Nop(); } PushIf(hints); }
private void Build(DThrow node, Hints hints, CompilerContext ctx) { Build(node.Expression, hints.Append(Push), ctx); AddLinePragma(node); cw.Fail(); }
private void Build(DBinaryOperation node, Hints hints, CompilerContext ctx) { var termLab = default(Label); var exitLab = default(Label); switch (node.Operator) { case BinaryOperator.Coalesce: exitLab = cw.DefineLabel(); Build(node.Left, hints.Remove(Last).Append(Push), ctx); cw.Dup(); cw.Brtrue(exitLab); cw.Pop(); Build(node.Right, hints.Append(Push), ctx); cw.MarkLabel(exitLab); cw.Nop(); break; case BinaryOperator.And: Build(node.Left, hints.Remove(Last).Append(Push), ctx); termLab = cw.DefineLabel(); exitLab = cw.DefineLabel(); cw.Brfalse(termLab); Build(node.Right, hints.Remove(Last).Append(Push), ctx); AddLinePragma(node); cw.Br(exitLab); cw.MarkLabel(termLab); AddLinePragma(node); cw.Push(false); cw.MarkLabel(exitLab); cw.Nop(); break; case BinaryOperator.Or: Build(node.Left, hints.Remove(Last).Append(Push), ctx); termLab = cw.DefineLabel(); exitLab = cw.DefineLabel(); cw.Brtrue(termLab); Build(node.Right, hints.Remove(Last).Append(Push), ctx); AddLinePragma(node); cw.Br(exitLab); cw.MarkLabel(termLab); AddLinePragma(node); cw.Push(true); cw.MarkLabel(exitLab); cw.Nop(); break; case BinaryOperator.Is: { var pat = (DPattern)node.Right; AddLinePragma(node); PreinitPattern(pat, hints.Remove(Last)); Build(node.Left, hints.Remove(Last).Append(Push), ctx); BuildPattern(pat, hints, ctx); } break; default: Build(node.Left, hints.Remove(Last).Append(Push), ctx); Build(node.Right, hints.Remove(Last).Append(Push), ctx); AddLinePragma(node); EmitBinaryOp(node.Operator); break; } PopIf(hints); }