Пример #1
0
        internal override void Accept(NodeFnDef fn)
        {
            // Leaves the function on the stack
            Accept(fn as NodeFnExpr);

            // Assign it to a thing
            if (fn.isGlobal)
            { // I hate nesting ifs without brackets...
                // The only valid node here will be an identifier
                if (fn.target is NodeIdentifier)
                {
                    builder.currentLineNumber = fn.target.EndLine;
                    builder.OpGStore((fn.target as NodeIdentifier).image);
                }
                else log.Error(fn.target.location, "Function target must be an identifier when assigning to the global namespace.");
            }
            else
            { // I really hate nesting ifs without brackets...
                if (fn.target is NodeIdentifier)
                {
                    builder.currentLineNumber = fn.target.EndLine;
                    builder.OpKStore((fn.target as NodeIdentifier).image);
                }
                // TODO check all the things plz
                else log.Error(fn.target.location, "Invalid function target.");
            }

            // We'll always have a value on the stack here, pop the value if we don't need it
            if (!fn.isResultRequired)
                builder.OpPop();
        }
Пример #2
0
 void ASTVisitor.Accept(NodeFnDef value)
 {
     Accept(value);
 }
Пример #3
0
        private Node ParseFn(bool isGenerator = false)
        {
            // Use the location of 'fn' as the location of this function.
            // The end of the function can be determined by the end of
            // it's body, so it's only expected to rely on the
            // line/col fields for functions.
            var loc = Location;
            // The first token we'll have is 'fn', so skip it.
            Advance();

            // We'll use this later, after checking for a name
            NodeFnExpr fn;

            // Next, check if there's an open brace.
            // If an open brace follows 'fn', it must be a lambda,
            // otherwise it's a definition, we need a location.
            if (Check(ASSIGN) || Check(OPEN_CURLY_BRACE))
            {
                fn = new NodeFnExpr(loc);
                fn.fullAnon = true;
            }
            else if (!Check(OPEN_BRACE))
            {
                fn = new NodeFnDef(loc);
                (fn as NodeFnDef).target = PrimaryExpression(false);
            }
            else fn = new NodeFnExpr(loc);
            fn.isGenerator = isGenerator;

            if (!fn.fullAnon)
            {
                // Hope that this is the open brace we seek.
                // TODO If not, maybe I should try to recover better.
                Expect(OPEN_BRACE,
                    "Expected an open brace ('(') to start the function parameter list.");

                // Now, we need to get the argument list.
                while (true)
                {
                    if (!TokensRemain)
                    {
                        log.Error(tokens[-1].location, "End of file reached, expected a parameter declaration.");
                        break;
                    }

                    // Break out early if we see a close brace.
                    // Even if it's not at the right time, it's
                    // a safe place to break.
                    if (Check(CLOSE_BRACE))
                        break;
                    // Next check for a parameter.
                    string paramName;
                    // If there's an identifier, it's a param
                    if (ExpectIdentifier(out paramName, "Expected identifier to name function parameter."))
                        fn.paramNames.Add(paramName);
                    // Otherwise, let's try to get the next param immediately
                    // rather than skipping or fumbling with more tokens.
                    else continue;
                    if (Check(ASSIGN))
                    {
                        Advance();
                        if (!TokensRemain)
                        {
                            log.Error(tokens[-1].location, "Expected expression for default parameter value, but the end of the file was reached.");
                            return fn;
                        }
                        fn.defaultParams.Add(Expression());
                    }
                    else if (fn.defaultParams.Count > 0)
                        fn.defaultParams.Add(new NodeNull(null));
                    // TODO check for vargs.
                    // If there's a comma, we expect there to be more parameters.
                    // Simply skip the comma and prepare for more.
                    if (Check(COMMA))
                        Advance();
                    // No more parameters, break out.
                    else break;
                }

                // Param lists end with ')', so look for it.
                Expect(CLOSE_BRACE,
                    "Expected a close brace (')') to end the function parameter list.");
            }

            // If the function is declared with an assign operator, it shouldn't be void.
            if (TokensRemain && Current.type == ASSIGN)
            {
                if (fn.isGenerator)
                    log.Error(Location, "Generators must be declared void.");
                Advance();
                fn.isVoid = false;
            }
            else fn.isVoid = true;

            // Finally, we get the body of the function.
            // Whether or not a function is void, its body is always an expression.

            if (!TokensRemain)
            {
                log.Error(fn.location, "Expected expression for function body, but the end of the file was reached.");
                return fn;
            }

            SetCurrentFunction(fn);
            fn.body = Expression();
            ReleaseCurrentFunction();

            return fn;
        }