Exemple #1
0
        public static TYPE parseTypeSpecifier(iSCOPE context, out bool ref_val, out bool conc, out Span final)
        {
            TYPE type = null;

            bool opt = false;

            ref_val = false; conc = false;
            Token token = get();
            Token begin = token;

            if (token.code == TokenCode.Question)
            {
                forget(); token = get();
                opt             = true;
            }
            switch (token.code)
            {
            case TokenCode.As:
                forget();
                EXPRESSION example = PRIMARY.parse(null, context);
                type = example.type;
                if (type != null)
                {
                    type.setSpan(begin.span, example.span);
                    if (type is UNIT_REF)
                    {
                        (type as UNIT_REF).setSpecs(opt, true);
                    }
                }
                final = example.span;
                break;

            case TokenCode.Ref:        ref_val = true; forget(); goto ParseType;

            case TokenCode.Concurrent: conc = true; forget(); goto ParseType;

            case TokenCode.Val:                        forget(); goto ParseType;

            case TokenCode.LParen:
                // Seems to a tuple type
                type = TUPLE_TYPE.parse(context);
                context.add(type);
                final = type.span;
                break;

            default:
                // forget();
ParseType:
                UNIT_REF unitRef = UNIT_REF.parse(null, opt, context);
                if (unitRef == null)     /* An error was detected earlier */
                {
                    final = null; return(null);
                }
                final = unitRef.span;
                token = get();
                return(unitRef);
            }
            return(type);
        }
Exemple #2
0
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public static void parse(bool hidden, bool final, Token start, iSCOPE context)
        {
            Debug.Indent();
            Debug.WriteLine("Entering CONSTANT.parse");

            CONSTANT constant = new CONSTANT();

            // 'const' and 'is' keywords were already parsed
            Token token = get();

            if (token.code == TokenCode.End)
            {
                forget(); goto FinalActions;
            }                                                                 // empty list

            while (true)
            {
                EXPRESSION left = EXPRESSION.parse(null, context);
                token = get();
                if (token.code == TokenCode.DotDot)   // range
                {
                    forget();
                    EXPRESSION right = EXPRESSION.parse(null, context);
                    BINARY     range = new BINARY(left, right);
                    range.setSpan(left.span, right.span);
                    range.parent = constant;
                    constant.constants.Add(range);
                }
                else // single expression
                {
                    left.parent = constant;
                    constant.constants.Add(left);
                }
                token = get();
                if (token.code == TokenCode.Comma)
                {
                    forget(); continue;
                }
                if (token.code == TokenCode.End)
                {
                    forget(); break;
                }
                else
                {
                    error(token, "syntax-error"); break;
                }
            }
FinalActions:
            constant.setSpecs(hidden, final);
            context.add(constant);
            constant.parent = context.self;
            constant.setSpan(start, token);

            Debug.WriteLine("Exiting CONSTANT.parse");
            Debug.Unindent();
        }
Exemple #3
0
        /// <summary>
        ///
        /// </summary>
        /// <syntax>
        /// Try : try
        ///          StatementList
        ///       catch ( [ Identifier : ] UnitType )
        ///          [ StatementList ]
        ///     { catch ( [ Identifier : ] UnitType )
        ///          [ StatementList ]
        ///     }
        ///     [ else [ StatementsList ] ]
        ///       end
        /// </syntax>
        /// <returns></returns>
        public static void parse(iSCOPE context)
        {
            Token token = get();
            Token begin = token;

            if (token.code != TokenCode.Try)   // Compiler error
            {
            }
            forget();

            TRY result = new TRY();

            Context.enter(result);

            BODY.parse(TokenCode.Catch, TokenCode.ERROR, TokenCode.ERROR, result);

            while (true)
            {
                token = get();
                if (token.code != TokenCode.Catch)
                {
                    break;
                }
                CATCH.parse(result);
            }
            token = get();
            if (token.code == TokenCode.Else)
            {
                forget();
                BODY.parse(TokenCode.End, TokenCode.ERROR, TokenCode.ERROR, context);
            }
            token = get();
            if (token.code != TokenCode.End)   // Syntax error
            {
            }
            forget();

            result.setSpan(begin, token);
            context.add(result);
            Context.exit();
        }
Exemple #4
0
        /// <summary>
        ///
        /// </summary>
        /// <syntax>
        /// Loop    : while BooleanExpression
        ///           loop
        ///           [ invariant PredicateList ]
        ///           [ StatementList ]
        ///           [ variant PredicateList ]
        ///           end [ loop ]
        ///
        ///         | loop
        ///           [ invariant PredicateList ]
        ///           [ StatementList ]
        ///           [ variant PredicateList ]
        ///           [ while BooleanExpression ]
        ///           end [ loop ]
        /// </syntax>
        /// <returns></returns>
        public static void parse(Token id, iSCOPE context)
        {
            Debug.Indent();
            Debug.WriteLine("Entering LOOP.parse");

            // If id != null, then 'id' is a loop label.
            // ':' after label is already parsed.
            LOOP loop = new LOOP();

            Context.enter(loop);

            Token token = get();
            Token begin = token;

            if (token.code == TokenCode.While)
            {
                forget();
                loop.prefix = true;
                EXPRESSION whileExpr = EXPRESSION.parse(null, context);
                token = get();
                if (token.code == TokenCode.Loop)
                {
                    forget();
                    loop.addw(whileExpr);
                    whileExpr.parent = loop;
                }
                else // Syntax error
                {
                    error(token, "no-loop");
                }

                token = get();
                if (token.code == TokenCode.Invariant)
                {
                    forget();
                    parseInvariant(loop);
                }

                BODY body = new BODY();
                body.parent = loop;
                loop.body   = body;

                Context.enter(body);
                token = get();
                BODY.parse(TokenCode.End, TokenCode.Variant, TokenCode.ERROR, body);
                body.setSpan(token, get());
                Context.exit();

                token = get();
                if (token.code == TokenCode.Variant)
                {
                    forget();
                    parseVariant(loop);
                }
            }
            else if (token.code == TokenCode.Loop)
            {
                loop.prefix = false;
                forget();
                token = get();
                if (token.code == TokenCode.Invariant)
                {
                    forget();
                    parseInvariant(loop);
                }

                BODY body = new BODY();
                body.parent = loop;
                loop.body   = body;

                Context.enter(body);
                token = get();
                BODY.parse(TokenCode.End, TokenCode.Variant, TokenCode.While, body);
                body.setSpan(token, get());
                Context.exit();

                token = get();
                if (token.code == TokenCode.Variant)
                {
                    forget();
                    parseVariant(loop);
                }
                token = get();
                if (token.code == TokenCode.While)
                {
                    forget();
                    EXPRESSION whileExpr = EXPRESSION.parse(null, context);
                    loop.addw(whileExpr);
                    whileExpr.parent = loop;
                }
            }
            else // Compiler error
            {
                error(token, "system-bug");
            }

            token = get();
            if (token.code != TokenCode.End)   // Syntax error
            {
                error(token, "no-end", "loop");
            }
            else
            {
                forget();
                token = get();
                if (token.code == TokenCode.Loop)
                {
                    forget();
                }
            }

            if (loop != null)
            {
                loop.setSpan(begin, token);
            }

            context.add(loop);
            Context.exit();

            Debug.WriteLine("Exiting LOOP.parse");
            Debug.Unindent();
        }
Exemple #5
0
        public static void parse(Token routineName, bool hidden, bool final, bool isOverride, int pure_safe, iSCOPE context)
        {
            ROUTINE routine = null;

            if (routineName.code == TokenCode.Init)
            {
                Debug.Indent();
                Debug.WriteLine("Entering INITIALIZER.parse");

                routine = new INITIALIZER();
                goto Init;
            }

            Debug.Indent();
            Debug.WriteLine("Entering ROUTINE.parse (" + routineName.image + ")");

            string image = routineName.image;
            Token  token = get(); // What's after the routine name?

            switch (routineName.image)
            {
            case "and":
                if (token.code == TokenCode.Then)
                {
                    forget();
                    image += " then";
                    Span span = new Span(routineName.span, token.span);
                    routineName = new Token(span, TokenCode.Identifier, image, new Category(CategoryCode.identifier));
                }
                break;

            case "or":
                token = get();
                if (token.code == TokenCode.Else)
                {
                    forget();
                    image += " else";
                    Span span = new Span(routineName.span, token.span);
                    routineName = new Token(span, TokenCode.Identifier, image, new Category(CategoryCode.identifier));
                }
                break;
            }
            routine = new ROUTINE(pure_safe, isOverride, routineName);
Init:
            routine.setSpecs(hidden, final);
            Context.enter(routine);

            if (routineName.code == TokenCode.Init)
            {
                goto Init2;
            }

            token = get();
            if (token.code == TokenCode.Alias)
            {
                forget();
                token         = expect(TokenCode.Identifier);
                routine.alias = new IDENTIFIER(token.image);
            }

            if (token.code == TokenCode.LBracket)
            {
                // Generic routine
                forget();
                while (true)
                {
                    var generic = FORMAL_GENERIC.parse(context);
                    routine.add(generic);

                    token = get();
                    switch (token.code)
                    {
                    case TokenCode.Comma:
                    case TokenCode.Semicolon: forget(); continue;

                    case TokenCode.RBracket:  forget(); goto Finish;

                    default: { /* Syntax error */ break; }
                    }
                }
Finish:
                ;
            }

Init2:
            token = get();
            if (token.code == TokenCode.LParen)
            {
                forget(); token = get();
                if (token.code == TokenCode.RParen)
                {
                    // Empty parameter list
                    forget();
                    goto Weiter;
                }
                while (true)
                {
                    VARIABLE.parse(false, false, false, false, null, null, routine);

                    token = get();
                    if (token.code == TokenCode.Comma)
                    {
                        forget(); continue;
                    }
                    if (token.code == TokenCode.Semicolon)
                    {
                        forget(); continue;
                    }
                    break;
                }
                expect(TokenCode.RParen);
            }

Weiter:
            token = get();
            if (token.code == TokenCode.Colon)
            {
                forget();

                bool ref_val, conc;  // TEMP SOLUTION
                Span span2;
                routine.type = VARIABLE.parseTypeSpecifier(routine, out ref_val, out conc, out span2);
                if (routine.type != null)
                {
                    routine.type.parent = routine;
                    routine.type.setSpan(span2);
                }
            }

            token = get();
            if (token.code == TokenCode.Require)
            {
                forget(); token = get();
                if (token.code == TokenCode.Else)
                {
                    forget(); routine.requireElse = true;
                }
                while (true)
                {
                    EXPRESSION precondition = EXPRESSION.parse(null, routine);
                    routine.addPre(precondition);
                    precondition.parent = routine;

                    token = get();
                    if (token.code == TokenCode.Is || token.code == TokenCode.Arrow)
                    {
                        break;
                    }
                }
            }

            if (token.code == TokenCode.Arrow)
            {
                forget();

                BODY body = new BODY();
                routine.routineBody = body;
                body.parent         = routine;

                Context.enter(body);
                EXPRESSION expression = EXPRESSION.parse(null, body);
                RETURN     ret        = new RETURN(expression);
                expression.parent = ret;
                ret.setSpan(expression.span);

                ret.parent = body;
                body.add(ret);
                body.setSpan(ret.span);

                Context.exit();
            }
            else if (token.code == TokenCode.Is)
            {
                forget(); token = get();
                if (token.code == TokenCode.Abstract)
                {
                    forget();
                    routine.isAbstract = true;
                }
                else if (token.code == TokenCode.Foreign)
                {
                    forget();
                    routine.isForeign = true;
                }
                else
                {
                    BODY body = new BODY();
                    body.parent         = routine;
                    routine.routineBody = body;

                    Context.enter(body);
                    BODY.parse(TokenCode.End, TokenCode.Ensure, TokenCode.ERROR, body);
                    Context.exit();
                }
                token = get();
                if (token.code == TokenCode.Ensure)
                {
                    forget();
                    token = get();
                    if (token.code == TokenCode.Then)
                    {
                        forget(); routine.ensureThen = true;
                    }
                    ENTITY.weAreWithinEnsure = true;
                    while (true)
                    {
                        EXPRESSION postcondition = EXPRESSION.parse(null, routine);
                        routine.addPre(postcondition);
                        postcondition.parent = routine;

                        token = get();
                        if (token.code == TokenCode.End)
                        {
                            forget(); break;
                        }
                    }
                    ENTITY.weAreWithinEnsure = false;
                }
                else if (!routine.isAbstract && !routine.isForeign)
                {
                    expect(TokenCode.End);
                }
            }
            token = get();
            if (token.code == TokenCode.Semicolon)
            {
                forget();
            }

            Context.exit();
            context.add(routine);

            routine.parent = context.self;
            routine.setSpan(routineName, token);

            if (routineName.code == TokenCode.Init)
            {
                Debug.WriteLine("Exiting INITIALIZER.parse");
            }
            else
            {
                Debug.WriteLine("Exiting ROUTINE.parse");
            }
            Debug.Unindent();
        }
Exemple #6
0
        public static void parse(iSCOPE context) // REWRITE!!
        {
            Token token = get();
            Token begin = token;

            if (token.code != TokenCode.Catch)   // Compiler error
            {
            }
            forget();

            CATCH handler = new CATCH();

            Context.enter(handler);

            token = get();
            if (token.code != TokenCode.LParen)   // Syntax error
            {
            }
            else
            {
                forget();
            }

            token = get();
            if (token.code != TokenCode.Identifier)   // Syntax error
            {
            }
            else
            {
                Token id = token;
                forget();
                token = get();
                if (token.code == TokenCode.Colon)
                {
                    forget();
                    // handler.identifier = id.image;

                    token = get();
                    if (token.code != TokenCode.Identifier)   // Syntax error
                    {
                    }
                    forget();
                    token = id;
                }
                UNIT_REF unit_ref = UNIT_REF.parse(null, false, context); // CHECK!!
                handler.unit_ref = unit_ref;
                unit_ref.parent  = handler;
            }

            token = get();
            if (token.code != TokenCode.RParen)   // Syntax error
            {
            }
            forget();

            BODY.parse(TokenCode.Catch, TokenCode.Else, TokenCode.End, handler);

            token = get(); // just to get the span...
            handler.setSpan(begin, token);

            Context.exit();
            context.add(handler);
        }
Exemple #7
0
        /// <summary>
        /// The function processes all kinds of statements including
        /// assignments, calls, and variable/constant declarations.
        /// </summary>
        /// <param name="context"></param>
        /// <returns>true, if any construct (a statement, or a simple declaration)
        /// was processed, and false otherwise.</returns>
        public static bool parse(iSCOPE context, TokenCode stop1, TokenCode stop2, TokenCode stop3)
        {
            Debug.Indent();
            Debug.WriteLine("Entering STATEMENT.parse");

            bool result = true;

            Token token = get();
            Token begin = token;

            if (token.code == stop1 && stop1 != TokenCode.ERROR)
            {
                goto Finish;
            }
            if (token.code == stop2 && stop2 != TokenCode.ERROR)
            {
                goto Finish;
            }
            if (token.code == stop3 && stop3 != TokenCode.ERROR)
            {
                goto Finish;
            }

            switch (token.code)
            {
            // case TokenCode.Pure: -- doesn't make any sense
            case TokenCode.Safe:
            case TokenCode.Routine:
                ROUTINE.parse(token, false, false, false, 0, context);
                break;

            case TokenCode.If:
                IF.parse(context);
                break;

            case TokenCode.While:
            case TokenCode.Loop:
                LOOP.parse(null, context);
                break;

            // Break
            //     : break [ Label ]
            //
            // Label
            //     : Identifier
            case TokenCode.Break:
                BREAK.parse(context);
                break;

            // Statement
            //     : ...
            //     | raise [ Expression ]
            case TokenCode.Raise:
                forget();
                RAISE.parse(token.span, context);
                break;

            // Statement
            //     : ...
            //     | check PredicatesList end
            //     | ...
            case TokenCode.Check:
                CHECK.parse(context);
                break;

            // Statement
            //     : ...
            //     | return [ Expression ]
            //     | ...
            case TokenCode.Return:
                forget();
                EXPRESSION expr = EXPRESSION.parse(null, context);    // can be null
                RETURN     ret  = new RETURN(expr);
                if (expr != null)
                {
                    expr.parent = ret;
                    ret.setSpan(begin.span, expr.span);
                }
                else
                {
                    ret.setSpan(begin);
                }

                context.add(ret);
                break;

            // Statement
            //     : ...
            //     | Try
            //     | ...
            //
            // Try
            //     : try { Statement } Catches [ Else ] end
            //
            // Catches
            //     : catch [ "(" [ Identifier ":" ] Type ")" ] { Statement }
            //
            // Else
            //     : else { Statement }
            case TokenCode.Try:
                TRY.parse(context);
                break;

            // Statement
            //     : ...
            //     | ? Identifier
            //     | ...
            //
            case TokenCode.Question:

                break;

            case TokenCode.Init:
                // Initializer call
                forget();
                Token start = token;

                DECLARATION init = Context.find(INITIALIZER.initName);
                EXPRESSION  initRef;
                if (init != null)
                {
                    initRef = new REFERENCE(init);
                }
                else
                {
                    initRef = new UNRESOLVED(context, new IDENTIFIER(INITIALIZER.initName));
                }

                CALL call = new CALL(initRef);
                token = expect(TokenCode.LParen);
                while (true)
                {
                    EXPRESSION argument = EXPRESSION.parse(null, context);
                    call.add(argument);
                    argument.parent = call;

                    token = get();
                    if (token.code == TokenCode.Comma)
                    {
                        forget(); continue;
                    }
                    break;
                }
                token = expect(TokenCode.RParen);
                call.setSpan(start.span, token.span);
                context.add(call);
                break;

            case TokenCode.Identifier:
            {
                // Several different cases:
                //   - a label in front of while/loop
                //   - a declaration
                //   - a statement

                forget();
                Token next = get();
                if (next.code == TokenCode.LParen)
                {
                    forget();
                    TokenCode codeAfter = saveTokensUntilRightParenth(next);
                    switch (codeAfter)
                    {
                    case TokenCode.Colon:
                    case TokenCode.Is:
                    // case TokenCode.Do:
                    case TokenCode.Arrow:
                        //This as a routine declaration!!
                        ROUTINE.parse(token, false, false, false, 0, context);
                        goto Weiter;
                    }
                }
                EXPRESSION attempt = EXPRESSION.parse(token, context);
                if (attempt is UNRESOLVED)
                {
                    // Might be a label or a declaration...
                    Token idd = new Token(attempt.span, TokenCode.Identifier,
                                          (attempt as UNRESOLVED).name.identifier,
                                          new Category(CategoryCode.identifier));
                    token = get();
                    switch (token.code)
                    {
                    case TokenCode.Is:
                    case TokenCode.Comma:
                        // This is definitely a declaration
                        forget();
                        VARIABLE.parse(false, false, false, false, idd, token, context);
                        goto Weiter;

                    case TokenCode.Colon:
                        forget();
                        Token token2 = get();
                        if (token2.code == TokenCode.While || token2.code == TokenCode.Loop)
                        {
                            // This is a real label! Don't 'forget()'.
                            LOOP.parse(idd, context);
                        }
                        else
                        {
                            // This is definitely a variable declaration.
                            // Don't forget()
                            VARIABLE.parse(false, false, false, false, idd, token, context);
                        }
                        goto Weiter;

                    default:
                        // Nothing to do; just going further
                        break;
                    }
                }
                // 'attempt' is something else: a call or the left part of an assignment
                token = get();
                if (token.code == TokenCode.Assign)
                {
                    forget();
                    EXPRESSION right = EXPRESSION.parse(null, context);
                    ASSIGNMENT res   = new ASSIGNMENT(attempt, right);
                    res.setSpan(attempt.span, right.span);
                    context.add(res);
                }
                else
                {
                    if (!(attempt is CALL))       // something's wrong
                    {
                        result = false;
                    }
                    context.add(attempt);
                }
Weiter:
                break;
            }

            case TokenCode.Const:
                // Something like
                //     const a is 5...
                // OR
                //     const is a, b, ... end
                forget(); token = get();
                if (token.code == TokenCode.Is)
                {
                    forget();
                    CONSTANT.parse(context);
                }
                else
                {
                    VARIABLE.parse(false, false, true, false, null, null, context);
                }
                break;

            default:
                // Something else, e.g., (a... or this...
                // Either a function call or an assignment.
                //
                //     this := ...
                //     (if cond then a else b).f ...
                //     ^

                EXPRESSION e = EXPRESSION.parse(null, context);
                if (e == null)
                {
                    // Either an error or just the end of statement sequence
                    result = false;
                    break;
                }
                token = get();
                if (token.code == TokenCode.Assign)
                {
                    forget();
                    EXPRESSION right      = EXPRESSION.parse(null, context);
                    ASSIGNMENT assignment = new ASSIGNMENT(e, right);
                    assignment.setSpan(e.span, right.span);
                    context.add(assignment);
                }
                else
                {
                    context.add(e);
                }
                break;
            }
Finish:
            Debug.WriteLine("Exiting STATEMENT.parse");
            Debug.Unindent();

            return(result);
        }
Exemple #8
0
        /// <summary>
        ///
        /// <syntax><code>
        /// Объявление-переменных
        ///         : Список-идентификаторов [ : Спецификатор-типа ] is Выражение
        ///         | Список-идентификаторов : Спецификатор-типа
        ///
        /// Спецификатор-типа
        ///         : [ ? | ref | val | concurrent ] Тип
        ///         | as Составное-имя
        /// </code></syntax>
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public static void parse(bool hidden, bool ffinal, bool isConst, bool isOverride, Token id, Token afterId, iSCOPE context)
        {
            Debug.Indent();
            Debug.WriteLine("Entering VARIABLE.parse");

            TYPE       type        = null;
            EXPRESSION initializer = null;

            bool RefVal  = false; // 'val' by default
            bool Conc    = false;
            bool Abstr   = false;
            bool Foreign = false;

            Token token = id;
            Span  final = null;

            // If id==null, then we just start processing the declaration.
            // In this case, always afterId==null.
            //
            // If id != null then it contains an identifier.
            // In this case, afterId contains ':', ',' or 'is' - three
            // options starting a declaration.

            List <Token> identifiers = new List <Token>();

            if (token == null)
            {
                // We just start parsing variable declaration
                token = get(); forget();
                identifiers.Add(token);

                // Parsing the rest of identifiers in the list (if any)
                while (true)
                {
                    token = get();
                    if (token.code != TokenCode.Comma)
                    {
                        break;
                    }
                    forget();
                    token = expect(TokenCode.Identifier);
                    identifiers.Add(token);
                }
            }
            else
            {
                if (afterId.code == TokenCode.Is)
                {
                    // id is ...
                    identifiers.Add(id);
                    token = afterId;
                }
                else if (afterId.code == TokenCode.Colon)
                {
                    // 'token' contains an identifier.
                    // Check what's after this identifier?
                    //
                    //  id : ...
                    //       ^
                    identifiers.Add(id);
                    token = afterId;
                }
                else if (afterId.code == TokenCode.Comma)
                {
                    // 'token' contains an identifier,
                    // and comma goes after it (comma was parsed already).
                    //
                    //  id, ...
                    //      ^
                    identifiers.Add(id);

                    // Parsing the rest of the list of identifiers.
                    while (true)
                    {
                        token = expect(TokenCode.Identifier);
                        identifiers.Add(token);
                        if (token.code != TokenCode.Comma)
                        {
                            break;
                        }
                        forget();
                    }
                }
                else
                {
                    // Syntax error
                    error(afterId, "syntax-error", "declaration");
                }
            }
            // Here, we have parsed the list of identifiers.
            // 'token' contains the token after the list.
            // Only two valid options are ':' or 'is'.

            if (token.code == TokenCode.Colon)
            {
                // Type is expected.
                if (afterId == null)
                {
                    forget();
                }
                type  = parseTypeSpecifier(context, out RefVal, out Conc, out final);
                token = get();
            }
            if (token.code == TokenCode.Is)
            {
                forget(); token = get();
                if (token.code == TokenCode.Abstract)
                {
                    forget();
                    Abstr = true;
                    final = token.span;
                }
                else if (token.code == TokenCode.Foreign)
                {
                    forget();
                    Foreign = true;
                    final   = token.span;
                }
                else
                {
                    forget();
                    initializer = EXPRESSION.parse(token, context);
                    if (type == null)
                    {
                        // Type inference
                        // initializer.calculateType();
                        type = initializer.type;
                    }
                    final = initializer.span;
                }
            }

            // Here, we have the list of identifiers, their type,
            // and perhaps the initializer.
            // Create the final node(s) for variable declaration(s)
            // out of identifier(s), type and initializer.

            foreach (Token ident in identifiers)
            {
                VARIABLE varDecl = new VARIABLE(new IDENTIFIER(ident), type, initializer);
                varDecl.setSpecs(hidden, ffinal);
                varDecl.setVarSpecs(isConst, isOverride, RefVal, Conc, Abstr, Foreign);
                varDecl.setSpan(ident.span, final != null ? final : ident.span);
                context.add(varDecl);

                varDecl.parent = context.self;

                if (type != null)
                {
                    type.parent = varDecl;
                }
                if (initializer != null)
                {
                    initializer.parent = varDecl;
                }
            }

            Debug.WriteLine("Exiting VARIABLE.parse");
            Debug.Unindent();
        }