Beispiel #1
0
        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);
        }
Beispiel #2
0
        private void Build(DIteratorLiteral node, Hints hints, CompilerContext ctx)
        {
            var dec = new DFunctionDeclaration(node.Location)
            {
                Body = node.YieldBlock
            };

            Build(dec, hints.Append(Iterator), ctx);
        }
Beispiel #3
0
    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
                })
Beispiel #4
0
    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);
            }
Beispiel #5
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);
            }
        }
Beispiel #6
0
    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);
    }
Beispiel #7
0
        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);
                }
            }
        }
Beispiel #8
0
        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);
            }
        }
Beispiel #9
0
 private void Build(DFunctionDeclaration node, Hints hints, CompilerContext ctx)
 {
     BuildFunctionDeclaration(node, hints.Remove(IteratorBody), ctx);
 }