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; }
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); }
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); }