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); }
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 GenerateConstructor(DFunctionDeclaration func, CompilerContext ctx) { if (func.Body is not null) { Build(func.Body, NoScope, new()); var count = 0; foreach (var(k, v) in currentScope.Locals) { if ((v.Data & VarFlags.Argument) != VarFlags.Argument) { count++; DirectPushScopeVar(k, new ScopeVar(0 | (v.Address << 8), v.Data)); cw.Tag(k); if ((v.Data & VarFlags.Const) != VarFlags.Const) { cw.Mut(); } } } cw.NewTuple(count); } else { cw.NewTuple(0); } if (func.Parameters.Count == 0) { AddLinePragma(func); cw.NewTuple(0); } else { for (var i = 0; i < func.Parameters.Count; i++) { var p = func.Parameters[i]; PushVariable(ctx, p.Name, p.Location); cw.Tag(p.Name); if (p.TypeAnnotation is not null) { foreach (var q in p.TypeAnnotation) { PushTypeInfo(ctx, q, p.Location); cw.Annot(); } } if (p is DTypeParameter { Mutable: true })
private void BuildFunctionDeclaration(DFunctionDeclaration node, Hints hints, CompilerContext ctx) { if (node.Name is not null || node.TargetTypeName is not null) { var flags = VarFlags.Const | VarFlags.Function; var addr = 0; var addFlag = IsStdCall(node); if (addFlag) { flags |= VarFlags.StdCall; } if (node.TypeName is null && node.Name is not null) { addr = AddVariable(node.Name, node.Location, flags, addFlag ? node.Parameters.Count : 0); }
private string GetMethodName(string name, DFunctionDeclaration node) { switch (name) { case "+": return(node.Parameters.Count == 0 ? Builtins.Plus : Builtins.Add); case "-": return(node.Parameters.Count == 0 ? Builtins.Neg : Builtins.Sub); case "get": return(Builtins.Get); case "set": return(Builtins.Set); case "*": return(Builtins.Mul); case "/": return(Builtins.Div); case "%": return(Builtins.Rem); case "<<": return(Builtins.Shl); case ">>": return(Builtins.Shr); case "^": return(Builtins.Xor); case "==": return(Builtins.Eq); case "!=": return(Builtins.Neq); case ">": return(Builtins.Gt); case "<": return(Builtins.Lt); case ">=": return(Builtins.Gte); case "<=": return(Builtins.Lte); case "!": return(Builtins.Not); case "~": return(Builtins.BitNot); default: return(name); } }
private bool IsStdCall(DFunctionDeclaration node) { if (options.NoOptimizations) { return(false); } if (node.TargetTypeName is not null) { return(false); } for (var i = 0; i < node.Parameters.Count; i++) { if (node.Parameters[i].DefaultValue is not null || node.Parameters[i].TypeAnnotation is not null || node.Parameters[i].IsVarArgs) { return(false); } } return(true); }
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(DFunctionDeclaration node, Hints hints, CompilerContext ctx) { if (node.Name != null) { var flags = VarFlags.Const | VarFlags.Function; var addr = 0; if (!node.IsMemberFunction) { addr = AddVariable(node.Name, node, flags); } else if (privateScope) { AddError(CompilerError.PrivateMethod, node.Location); } BuildFunctionBody(addr, node, hints, ctx); if (hints.Has(Push)) { cw.Dup(); } if (node.IsMemberFunction) { var realName = node.Name; if (!node.IsStatic) { realName = GetMethodName(realName, node); } if (node.Name == Builtins.Has || (!node.IsStatic && node.Name == Builtins.Type)) { AddError(CompilerError.OverrideNotAllowed, node.Location, node.Name); } var nameId = GetMemberNameId(realName); cw.Aux(nameId); var code = GetTypeHandle(node.TypeName, node.Location); if (node.IsStatic) { cw.SetMemberS(code); } else { cw.SetMember(code); } } AddLinePragma(node); if (node.IsMemberFunction) { cw.Nop(); } else { cw.PopVar(addr); } } else { BuildFunctionBody(-1, node, hints, ctx); AddLinePragma(node); cw.Nop(); PopIf(hints); } }
private void Build(DFunctionDeclaration node, Hints hints, CompilerContext ctx) { BuildFunctionDeclaration(node, hints.Remove(IteratorBody), ctx); }