예제 #1
0
        public override int Compile(FunctionContext context)
        {
            context.Line(FileName, Line);

            var isStatement = Parent is IBlockStatementExpression;

            if (Name == null && isStatement)
                throw new MondCompilerException(FileName, Line, "Function is never used");

            IdentifierOperand identifier = null;

            if (Name != null)
            {
                if (!context.DefineIdentifier(Name, true))
                    throw new MondCompilerException(FileName, Line, "Identifier '{0}' was previously defined in this scope", Name);

                identifier = context.Identifier(Name);
            }

            var functionContext = context.MakeFunction(Name);
            functionContext.Function(FileName, Name);

            context.PushFrame();

            for (var i = 0; i < Arguments.Count; i++)
            {
                var name = Arguments[i];

                if (!functionContext.DefineArgument(i, name))
                    throw new MondCompilerException(FileName, Line, "Identifier '{0}' was previously defined in this scope", name);
            }

            functionContext.Bind(functionContext.Label);
            functionContext.Enter();
            Block.Compile(functionContext);
            functionContext.LoadUndefined();
            functionContext.Return();

            context.PopFrame();

            context.Closure(functionContext.Label);

            if (identifier != null)
            {
                if (!isStatement) // statements should leave nothing on the stack
                    context.Dup();

                context.Store(identifier);

                if (isStatement)
                    return 0;
            }

            return 1;
        }
예제 #2
0
        public override void CompileBody(FunctionContext context)
        {
            var state      = context.DefineInternal("state");
            var enumerable = context.DefineInternal("enumerable");

            var stack      = 0;
            var bodyToken  = new Token(Token, TokenType.Fun, null);
            var body       = new SequenceBodyExpression(bodyToken, null, Block, "moveNext", state, enumerable);
            var seqContext = new SequenceContext(context.Compiler, "moveNext", body, context);

            var getEnumerator = context.MakeFunction("getEnumerator");

            getEnumerator.Function(getEnumerator.FullName);
            getEnumerator.Bind(getEnumerator.Label);
            getEnumerator.Enter();
            getEnumerator.Load(enumerable);
            getEnumerator.Return();

            var dispose = context.MakeFunction("dispose");

            dispose.Function(dispose.FullName);
            dispose.Bind(dispose.Label);
            dispose.Enter();
            dispose.LoadUndefined();
            dispose.Return();

            stack += context.Bind(context.Label);
            stack += context.Enter();

            if (OtherArguments != null)
            {
                stack += context.VarArgs(Arguments.Count);
            }

            stack += context.Load(context.Number(0));
            stack += context.Store(state);

            stack += context.NewObject();

            stack += context.Dup();
            stack += context.LoadUndefined();
            stack += context.Swap();
            stack += context.StoreField(context.String("current"));

            stack += context.Dup();
            stack += body.Compile(seqContext);
            stack += context.Swap();
            stack += context.StoreField(context.String("moveNext"));

            stack += context.Dup();
            stack += context.Closure(getEnumerator.Label);
            stack += context.Swap();
            stack += context.StoreField(context.String("getEnumerator"));

            stack += context.Dup();
            stack += context.Closure(dispose.Label);
            stack += context.Swap();
            stack += context.StoreField(context.String("dispose"));

            stack += context.Store(enumerable);

            stack += context.Load(enumerable);
            stack += context.Return();

            CheckStack(stack, 0);
        }
예제 #3
0
        public override int Compile(FunctionContext context)
        {
            var isStatement    = Parent is IBlockExpression;
            var shouldBeGlobal = context.ArgIndex == 0 && context.Compiler.Options.MakeRootDeclarationsGlobal;
            var shouldStore    = Name != null;

            IdentifierOperand identifier = null;

            if (shouldStore && !shouldBeGlobal)
            {
                if (!context.DefineIdentifier(Name, true))
                {
                    throw new MondCompilerException(this, CompilerError.IdentifierAlreadyDefined, Name);
                }

                identifier = context.Identifier(Name);
            }

            // compile body
            var functionContext = context.MakeFunction(Name ?? DebugName);

            functionContext.Function(functionContext.FullName);
            functionContext.Position(Token);
            functionContext.PushScope();

            for (var i = 0; i < Arguments.Count; i++)
            {
                var name = Arguments[i];

                if (!functionContext.DefineArgument(i, name))
                {
                    throw new MondCompilerException(this, CompilerError.IdentifierAlreadyDefined, name);
                }
            }

            if (OtherArguments != null && !functionContext.DefineArgument(Arguments.Count, OtherArguments))
            {
                throw new MondCompilerException(this, CompilerError.IdentifierAlreadyDefined, OtherArguments);
            }

            CompileBody(functionContext);
            functionContext.PopScope();

            // assign result
            var stack = 0;

            context.Position(Token); // debug info
            stack += context.Closure(functionContext.Label);

            if (shouldStore)
            {
                if (!isStatement) // statements should leave nothing on the stack
                {
                    stack += context.Dup();
                }

                if (!shouldBeGlobal)
                {
                    stack += context.Store(identifier);
                }
                else
                {
                    stack += context.LoadGlobal();
                    stack += context.StoreField(context.String(Name));
                }

                if (isStatement)
                {
                    CheckStack(stack, 0);
                    return(stack);
                }
            }

            CheckStack(stack, 1);
            return(stack);
        }