Esempio n. 1
0
        private static void ParsePostfixExpr(ParseState state)
        {
            // What we do is optional qualification of names:
            // PostfixExpr ::= PrimaryExpr
            //               | PrimaryExpr "(" ArgumentList ")"
            //
            // ArgumentList ::= <empty> | Expr { "," Expr }
            //
            // How a full C-like grammar looks like:
            // PostfixExpr ::= PrimaryExpr
            //               | PostfixExpr "." Name
            //               | PostfixExpr "[" Expr "]"
            //               | PostfixExpr "(" ArgumentList ")"
            //
            // And how that would be parsed:
            // ParsePrimaryExpr(state);
            // while (state.IsOp(".", "[", "(")) {
            //   var op = (string) state.Value;
            //   state.Advance();
            //   switch (op) { etc... }

            ParsePrimaryExpr(state);

            if (state.IsOp("("))
            {
                // TODO Optimization: if invocation target is syntactically known: resolve now (and check param types)
                state.Advance();
                int n = ParseArgumentList(state);
                state.Advance(")");
                state.Target.EmitCall(n);
            }
        }
Esempio n. 2
0
        private static void ParseUnaryExpr(ParseState state)
        {
            if (state.IsOp("-"))
            {
                state.Advance();
                ParseUnaryExpr(state);

                state.Target.EmitCode(OpCode.Neg);
            }
            else if (state.IsOp("+"))
            {
                state.Advance();
                ParseUnaryExpr(state);

                state.Target.EmitCode(OpCode.Pos);
            }
            else if (state.IsOp("not"))
            {
                state.Advance();
                ParseUnaryExpr(state);

                state.Target.EmitCode(OpCode.Not);
            }
            else
            {
                ParsePostfixExpr(state);
            }
        }
Esempio n. 3
0
        private static void ParsePredicateExpr(ParseState state)
        {
            ParseAdditiveExpr(state);

            if (state.IsOp("is"))
            {
                state.Advance();
                ParseTypeCheck(state);
            }
            else if (state.IsOp("not"))
            {
                state.Advance();
                if (state.IsOp("in"))
                {
                    state.Advance();
                    ParseMemberCheck(state, true);
                }
                else
                {
                    object o = state.IsSymbol ? state.Value : state.Token;
                    throw SyntaxError(
                              state.Position,
                              "Expected 'not in', but got 'not {0}'", o);
                }
            }
            else if (state.IsOp("in"))
            {
                state.Advance();
                ParseMemberCheck(state, false);
            }
            else if (state.IsOp(_relops))
            {
                ParseRelationalExpr(state);
            }
        }
Esempio n. 4
0
        private static void ParseMemberCheck(ParseState state, bool negate)
        {
            // Syntax: ... [not] in (AdditiveExpr {, AdditiveExpr})
            // The 'in' and optional 'not' is already consumed

            // Notice that A in (B, C) is just a convenient abbreviation
            // for A = B or A = C, so we can generate code like this:
            //             B                       C
            //         A   A    T/F            A   A    T/F
            //   A     A   A     A       A     A   A     A       A             F                         T
            // A . Dup . B . Ceq . Jit@1 . Dup . C . Ceq . Jit@1 . Pop . False . Jmp@end . @1:Pop . True .
            //     ---------------------   ---------------------
            // and when negated ("not in") we emit the same code as above
            // but with the opcodes True and False exchanged.

            state.Advance("(");

            if (state.IsOp(")"))
            {
                // Special case: "foo in ()" is always false
                state.Advance();
                state.Target.EmitCode(OpCode.Pop);
                state.Target.EmitValue(false);
            }
            else
            {
                var mid = state.Target.ObtainLabel();
                var end = state.Target.ObtainLabel();

                state.Target.EmitCode(OpCode.Dup);
                ParseAdditiveExpr(state);
                state.Target.EmitCode(OpCode.Ceq);
                state.Target.EmitJump(OpCode.Jit, mid);

                while (state.IsOp(","))
                {
                    state.Advance();
                    state.Target.EmitCode(OpCode.Dup);
                    ParseAdditiveExpr(state);
                    state.Target.EmitCode(OpCode.Ceq);
                    state.Target.EmitJump(OpCode.Jit, mid);
                }

                state.Advance(")");

                state.Target.EmitCode(OpCode.Pop);
                state.Target.EmitValue(negate);
                state.Target.EmitJump(OpCode.Jmp, end);
                state.Target.DefineLabel(mid);
                state.Target.EmitCode(OpCode.Pop);
                state.Target.EmitValue(!negate);
                state.Target.DefineLabel(end);
            }
        }
Esempio n. 5
0
        private static Program Parse(string clause)
        {
            var program = new Program();
            var state   = new ParseState(clause);

            state.Advance();

            if (state.IsEnd)
            {
                // Special case: empty clause is always true:
                program.EmitValue(true);
                return(program);
            }

            ParseClause(state, program);

            if (!state.IsEnd)
            {
                throw SyntaxError(state.Index, "Expected end of input");
            }

            program.SqueezeNops();

            return(program);
        }
Esempio n. 6
0
        private static void ParseAdditiveExpr(ParseState state)
        {
            ParseMultiplicativeExpr(state);

            while (state.IsOp("+", "-"))
            {
                var op = (string)state.Value;
                state.Advance();
                ParseMultiplicativeExpr(state);

                switch (op)
                {
                case "+":
                    state.Target.EmitCode(OpCode.Add);
                    break;

                case "-":
                    state.Target.EmitCode(OpCode.Sub);
                    break;

                default:
                    throw ParserBug("Unexpected operator: {0}", op);
                }
            }
        }
Esempio n. 7
0
        private static void ParseMultiplicativeExpr(ParseState state)
        {
            ParseUnaryExpr(state);

            while (state.IsOp("*", "/", "%"))
            {
                var op = (string)state.Value;
                state.Advance();
                ParseUnaryExpr(state);

                switch (op)
                {
                case "*":
                    state.Target.EmitCode(OpCode.Mul);
                    break;

                case "/":
                    state.Target.EmitCode(OpCode.Div);
                    break;

                case "%":
                    state.Target.EmitCode(OpCode.Rem);
                    break;

                default:
                    throw ParserBug("Unexpected operator: {0}", op);
                }
            }
        }
Esempio n. 8
0
        private static void ParseRelationalExpr(ParseState state)
        {
            // We support chained comparison, eg, A < B = C <= D < E
            // (like Python, but different from C, JavaScript, et al.)
            //
            // Notice that A op B op C says nothing about how A relates to C.
            //
            // The code generated evaluates each operand at most once.
            // For example, in "1 < 1+1 < 1-1 < 2*3", the sum is evaluated
            // only once and the multiplication is not evaluated at all.
            //
            // Expression: A op B op C etc.
            // Stack:  A   A     B     B      B     B     C     C      C
            //             B     A    F/T           C     B    F/T
            //                   B                        C
            // Code:   A ; B ; Dup1 ; Cop ; Jif@1 ; C ; Dup1 ; Cop ; Jif@1 ; Pop ; True ; Jmp@end ; @1: Pop ; False
            //                 ------------------       ------------------
            //
            // Notice that emitting Jop' in place of Cop+Jif where op' is the negation of op
            // (that is, ne for eq, ge for lt, etc.) is a valid optimization for 2VL, but
            // it is not correct for 3VL because the "excluded third" doesn't hold.
            //
            // The binary case "A op B " is simplified to:  A ; B ; Cop (end)
            //
            // The initial AdditiveExpr has already been consumed, and
            // the current token is known to be a relop (see calling code).

            int operatorCount = 0;
            var falsum        = state.Target.ObtainLabel();
            var end           = state.Target.ObtainLabel();

            while (state.IsOp(_relops))
            {
                operatorCount += 1;

                var op = (string)state.Value;
                state.Advance();
                ParseAdditiveExpr(state);

                if (operatorCount == 1 && !state.IsOp(_relops))
                {
                    // Code for the (frequent) binary case:
                    state.Target.EmitCode(GetComp(op));
                    return;
                }

                // Code for the (general) chained case:
                state.Target.EmitCode(OpCode.Dup1);
                state.Target.EmitCode(GetComp(op));
                state.Target.EmitJump(OpCode.Jif, falsum);
            }

            state.Target.EmitCode(OpCode.Pop);
            state.Target.EmitValue(true);
            state.Target.EmitJump(OpCode.Jmp, end);
            state.Target.DefineLabel(falsum);
            state.Target.EmitCode(OpCode.Pop);
            state.Target.EmitValue(false);
            state.Target.DefineLabel(end);
        }
Esempio n. 9
0
        private static void Consume(string expected, ref ParseState <char> state)
        {
            var oldCol = state.ComputeSourcePos().Col;

            AssertEqual(expected.AsSpan(), state.LookAhead(expected.Length));
            state.Advance(expected.Length);
            Assert.Equal(oldCol + expected.Length, state.ComputeSourcePos().Col);
        }
Esempio n. 10
0
        private static void ParsePrimary(ParseState state, Program program)
        {
            if (state.CurrentToken == TokenType.LParen)
            {
                state.Advance();

                ParseClause(state, program);

                state.ExpectToken(TokenType.RParen);
                state.Advance();
            }
            else
            {
                ParseExpression(state, program);

                if (state.IsCompOp)                 // expr op expr
                {
                    var inst = GetInstruction(state.CurrentToken);

                    state.Advance();

                    ParseExpression(state, program);

                    program.Emit(inst);
                }
                else if (state.IsSymbol("NOT"))                 // expr NOT IN (expr, expr, etc)
                {
                    state.Advance();
                    state.ExpectSymbol("IN");

                    ParseInValueList(state, program, true);
                }
                else if (state.IsSymbol("IN"))                 // expr IN (expr, expr, etc)
                {
                    ParseInValueList(state, program, false);
                }
                else if (state.IsSymbol("IS"))                 // expr IS [NOT] NULL
                {
                    state.Advance();

                    bool negate = false;

                    if (state.IsSymbol("NOT"))
                    {
                        negate = true;
                        state.Advance();
                    }

                    state.ExpectSymbol("NULL");
                    state.Advance();

                    program.Emit(negate ? Instruction.NotNull : Instruction.IsNull);
                }
                else
                {
                    throw SyntaxError(state.Index, "Expected expr, IN, or IS; got {0}",
                                      state.CurrentTokenString);
                }
            }
        }
Esempio n. 11
0
        private static void Consume(char expected, ref ParseState <char> state)
        {
            var oldCol = state.ComputeSourcePos().Col;

            Assert.True(state.HasCurrent);
            Assert.Equal(expected, state.Current);
            state.Advance();
            Assert.Equal(oldCol + 1, state.ComputeSourcePos().Col);
        }
Esempio n. 12
0
        private static void ParseConditionalExpr(ParseState state)
        {
            ParseNullCoalesceExpr(state);

            if (state.IsOp("?"))
            {
                state.Advance();

                // With 2VL, the code for P ? A : B is as simple as:
                //
                // [P]  Jif@1  [A]  Jmp@end  [B]
                //
                // With 3VL we want null ? A : B to evaluate to null.
                // There are now three cases, and the code becomes:
                //
                // [P]  Dup  Jit@1  Jif@2  Null  Jmp@end  @1: Pop  [A]  Jmp@end  @2: [B]

                var consequent  = state.Target.ObtainLabel();
                var alternative = state.Target.ObtainLabel();
                var end         = state.Target.ObtainLabel();

                state.Target.EmitCode(OpCode.Dup);
                state.Target.EmitJump(OpCode.Jit, consequent);
                state.Target.EmitJump(OpCode.Jif, alternative);
                state.Target.EmitCode(OpCode.Null);
                state.Target.EmitJump(OpCode.Jmp, end);

                state.Target.DefineLabel(consequent);
                state.Target.EmitCode(OpCode.Pop);

                ParseConditionalExpr(state);                 // consequent

                state.Advance(":");

                state.Target.EmitJump(OpCode.Jmp, end);

                state.Target.DefineLabel(alternative);

                ParseConditionalExpr(state);                 // alternative

                state.Target.DefineLabel(end);
            }
        }
Esempio n. 13
0
        private static void ParseTypeCheck(ParseState state)
        {
            // Syntax: ... is [not] type (the 'is' is already consumed)
            bool negate = false;

            if (state.IsOp("not"))
            {
                negate = true;
                state.Advance();
            }

            if (state.IsOp("null"))
            {
                state.Advance();
                state.Target.EmitCode(OpCode.Cin);
                if (negate)
                {
                    state.Target.EmitCode(OpCode.Not);
                }
            }
            else if (state.IsName)
            {
                // TODO parse Name {'.' Name}, useful for: ... is ESRI.ArcGIS.Display.IColor
                var type = (string)state.Value;
                state.Advance();
                state.Target.EmitValue(type);
                state.Target.EmitCode(OpCode.Is);
                if (negate)
                {
                    state.Target.EmitCode(OpCode.Not);
                }
            }
            else
            {
                object o = state.IsSymbol ? state.Value : state.Token;
                throw SyntaxError(
                          state.Position,
                          "Expected 'is null' or 'is Type', but got 'is {0}'", o);
            }
        }
Esempio n. 14
0
        private static void ParseExpression(ParseState state, Program program)
        {
            // TODO Allow richer expressions: arithmetic

            switch (state.CurrentToken)
            {
            case TokenType.Symbol:
                if (state.IsSymbol("FALSE"))
                {
                    program.EmitValue(false);
                }
                else if (state.IsSymbol("TRUE"))
                {
                    program.EmitValue(true);
                }
                else if (state.IsSymbol("NULL"))
                {
                    program.EmitValue(null);
                }
                else                         // column reference to be looked up
                {
                    program.EmitValue(state.TokenValue);
                    program.Emit(Instruction.Get);
                }

                state.Advance();
                break;

            case TokenType.String:
            case TokenType.Number:
                program.EmitValue(state.TokenValue);
                state.Advance();
                break;

            default:
                throw SyntaxError(state.Index, "Expected Symbol, String, or Number; got {0}",
                                  state.CurrentTokenString);
            }
        }
Esempio n. 15
0
        private static void ParseLogicalAndExpr(ParseState state)
        {
            ParsePredicateExpr(state);

            while (state.IsOp("and"))
            {
                state.Advance();

                ParsePredicateExpr(state);

                state.Target.EmitCode(OpCode.And);
            }
        }
Esempio n. 16
0
        //private static void ParseLogicalOrExpr(ParseState state)
        //{
        //	// LogicalOrExpr ::= LogicalAndExpr { "||" LogicalAndExpr }
        //	//
        //	// Semantics: A || B = if A then A else B (like JavaScript)
        //	//
        //	// For the code generated: see ParseLogicalAndExpr and s/JIF/JIT/g

        //	ParseLogicalAndExpr(state);

        //	if (state.IsOp("||")) // Could drop this if; unused labels are harmless
        //	{
        //		var end = state.Target.ObtainLabel();

        //		while (state.IsOp("||"))
        //		{
        //			state.Advance();

        //			state.Target.EmitCode(OpCode.Dup);
        //			state.Target.EmitJump(OpCode.Jit, end);
        //			state.Target.EmitCode(OpCode.Pop);

        //			ParseLogicalAndExpr(state);
        //		}

        //		state.Target.DefineLabel(end);
        //	}
        //}

        //private static void ParseLogicalAndExpr(ParseState state)
        //{
        //	// LogicalAndExpr ::= RelationalExpr { "&&" RelationalExpr }
        //	//
        //	// Semantics: A && B = if A then B else A (like JavaScript)
        //	//
        //	// Expression:  A && B
        //	// Stack:  A // A A // A      // _   // B // *
        //	// Code:   A // DUP // JIF @1 // POP // B // @1: (end)
        //	//              --------------------
        //	//
        //	// Expression:  A && B && C
        //	// Stack:  A // A A // A      // _   // B // B B // B      // _   // C // *
        //	// Code:   A // DUP // JIF @1 // POP // B // DUP // JIF @1 // POP // C // @1: (end)
        //	//              --------------------         --------------------

        //	ParseRelationalExpr(state);

        //	if (state.IsOp("&&")) // Could drop this if; unused labels are harmless
        //	{
        //		var end = state.Target.ObtainLabel();

        //		while (state.IsOp("&&"))
        //		{
        //			state.Advance();

        //			state.Target.EmitCode(OpCode.Dup);
        //			state.Target.EmitJump(OpCode.Jif, end);
        //			state.Target.EmitCode(OpCode.Pop);

        //			ParseRelationalExpr(state);
        //		}

        //		state.Target.DefineLabel(end);
        //	}
        //}

        #endregion

        private static void ParseLogicalOrExpr(ParseState state)
        {
            ParseLogicalAndExpr(state);

            while (state.IsOp("or"))
            {
                state.Advance();

                ParseLogicalAndExpr(state);

                state.Target.EmitCode(OpCode.Or);
            }
        }
Esempio n. 17
0
        private static void ParseInValueList(ParseState state, Program program, bool negate)
        {
            // Notice:
            // "x IN (a, b, c)" is equivalent to "x = a OR x = b OR x = c";
            // we compile this to: [expr Mark Exch {Dup expr IsEq Exch} Pop Or]
            // "x NOT IN (a,b,c)" is equivalent to "x <> a AND x <> b AND x <> c";
            // we compile this to: [expr Mark Exch {Dup expr NotEq Exch} Pop And]

            state.Advance();             // eat the "IN" token

            state.ExpectToken(TokenType.LParen);
            state.Advance();

            program.Emit(Instruction.Mark);
            program.Emit(Instruction.Exch);

            program.Emit(Instruction.Dup);
            ParseExpression(state, program);
            program.Emit(negate ? Instruction.NotEq : Instruction.IsEq);
            program.Emit(Instruction.Exch);

            while (state.IsToken(TokenType.Comma))
            {
                state.Advance();

                program.Emit(Instruction.Dup);
                ParseExpression(state, program);
                program.Emit(negate ? Instruction.NotEq : Instruction.IsEq);
                program.Emit(Instruction.Exch);
            }

            state.ExpectToken(TokenType.RParen);
            state.Advance();

            program.Emit(Instruction.Pop);
            program.Emit(negate ? Instruction.And : Instruction.Or);
        }
Esempio n. 18
0
        private static EvaluatorEngine Compile(string text, int index, out int length,
                                               StringComparison comparison)
        {
            int anchor = index;
            var state  = new ParseState(text, index, new EvaluatorEngine(), comparison);

            state.Advance();

            ParseExpression(state);

            state.Target.EmitCode(OpCode.End);
            state.Target.Commit();

            length = state.Position - anchor;
            return(state.Target);
        }
Esempio n. 19
0
        private static void ParseFactor(ParseState state, Program program)
        {
            bool negate = false;

            if (state.IsSymbol("NOT"))
            {
                negate = true;
                state.Advance();
            }

            ParsePrimary(state, program);

            if (negate)
            {
                program.Emit(Instruction.Neg);
            }
        }
Esempio n. 20
0
        private static int ParseArgumentList(ParseState state)
        {
            if (state.IsOp(")"))
            {
                return(0);                // the empty list
            }

            int count = 1;

            ParseExpression(state);

            while (state.IsOp(","))
            {
                state.Advance();
                count += 1;
                ParseExpression(state);
            }

            return(count);            // #args in list
        }
Esempio n. 21
0
        private static void ParseTerm(ParseState state, Program program)
        {
            bool singleton = true;
            int  pc        = program.EmitNop();

            ParseFactor(state, program);

            while (state.IsSymbol("AND"))
            {
                singleton = false;
                state.Advance();
                ParseFactor(state, program);
            }

            if (!singleton)
            {
                program.Emit(pc, Instruction.Mark);
                program.Emit(Instruction.And);
            }
        }
Esempio n. 22
0
        private static void ParseNullCoalesceExpr(ParseState state)
        {
            ParseLogicalOrExpr(state);

            if (state.IsOp("??"))
            {
                var end = state.Target.ObtainLabel();
                var alt = state.Target.ObtainLabel();

                state.Advance();

                state.Target.EmitCode(OpCode.Dup);
                state.Target.EmitJump(OpCode.Jin, alt);
                state.Target.EmitJump(OpCode.Jmp, end);
                state.Target.DefineLabel(alt);
                state.Target.EmitCode(OpCode.Pop);

                ParseUnaryExpr(state);

                state.Target.DefineLabel(end);
            }
        }
Esempio n. 23
0
        public override IMatched <Unit> ParseStatement(ParseState state, Token[] tokens)
        {
            var mutable    = tokens[1].Text == "var";
            var fieldName  = tokens[3].Text;
            var assignment = fieldName.IsNotEmpty();

            state.Colorize(tokens, Color.Keyword, Color.Whitespace, Color.Identifier, Color.Whitespace, Color.Structure, Color.Whitespace,
                           Color.Keyword, Color.Whitespace);

            if (getExpression(state, ExpressionFlags.Standard).ValueOrCast <Unit>(out var expression, out var asUnit))
            {
                var matchField = newLabel("match");
                state.AddStatement(new AssignToNewField(false, matchField, expression));

                state.Advance();
                var caseParser = new CaseParser(fieldName, mutable, assignment, matchField, true, CaseType.Statement);
                if (caseParser.Scan(state).ValueOrOriginal(out _, out asUnit))
                {
                    var ifStatement = caseParser.If;
                    addMatchElse(ifStatement);
                    state.AddStatement(ifStatement);
                    state.Regress();

                    return(Unit.Matched());
                }
                else
                {
                    state.Regress();
                    return(asUnit);
                }
            }
            else
            {
                return(asUnit);
            }
        }
Esempio n. 24
0
        public override IMatched <Unit> ParseStatement(ParseState state, Token[] tokens)
        {
            var className = tokens[3].Text;

            Module.Global.ForwardReference(className);
            state.Colorize(tokens, Color.Keyword, Color.Whitespace, Color.Class);

            state.SkipEndOfLine();
            state.Advance();

            var mixins = new List <Mixin>();

            while (state.More)
            {
                var mixinIncludesParser = new MixinIncludesParser(mixins);
                if (mixinIncludesParser.Scan(state).If(out _, out var anyException))
                {
                }
                else if (anyException.If(out var exception))
                {
                    state.Regress();
                    return(failedMatch <Unit>(exception));
                }
                else
                {
                    break;
                }
            }

            state.SkipEndOfLine();
            state.Regress();

            if (getBlock(state).ValueOrCast <Unit>(out var block, out var asUnit))
            {
                var builder = new ClassBuilder(className, Parameters.Empty, "", new Expression[0], false, block, mixins);
                if (builder.Register().ValueOrOriginal(out _, out asUnit))
                {
                    var cls = new Class(builder);
                    state.AddStatement(cls);

                    var classItemsParser = new ClassItemsParser(builder);
                    while (state.More)
                    {
                        if (classItemsParser.Scan(state).If(out _, out var anyException))
                        {
                        }
                        else if (anyException.If(out var exception))
                        {
                            return(failedMatch <Unit>(exception));
                        }
                        else
                        {
                            break;
                        }
                    }

                    Module.Global.RegisterMixin(new Mixin(className));
                    return(Unit.Matched());
                }
                else
                {
                    return(asUnit);
                }
            }
            else
            {
                return(asUnit);
            }
        }
Esempio n. 25
0
        private static void ParsePrimaryExpr(ParseState state)
        {
            // PrimaryExpr ::= Number | String | Name | Name "." Name | "(" Expr ")"

            if (state.IsNumber)
            {
                var value = (double)state.Value;
                state.Advance();

                state.Target.EmitValue(value);
            }
            else if (state.IsString)
            {
                var value = (string)state.Value;
                state.Advance();

                state.Target.EmitValue(value);
            }
            else if (state.IsName)
            {
                var name = (string)state.Value;
                state.Advance();

                if (string.Equals(name, "null", state.Comparison))
                {
                    state.Target.EmitValue(null);
                }
                else if (string.Equals(name, "false", state.Comparison))
                {
                    state.Target.EmitValue(false);
                }
                else if (string.Equals(name, "true", state.Comparison))
                {
                    state.Target.EmitValue(true);
                }
                else
                {
                    if (state.IsOp("."))
                    {
                        string qualifier = name;
                        state.Advance();
                        if (!state.IsName)
                        {
                            var o = state.IsSymbol ? state.Value : state.Token;
                            throw SyntaxError(
                                      state.Position,
                                      "Expected '{0}.Name', but got '{0}.{1}'",
                                      qualifier, o);
                        }

                        name = (string)state.Value;
                        state.Advance();
                        state.Target.EmitValue(qualifier);
                        state.Target.EmitValue(name);
                        state.Target.EmitCode(OpCode.GetQualified);                         // Stack: ... qual name => value
                    }
                    else
                    {
                        state.Target.EmitValue(name);
                        state.Target.EmitCode(OpCode.Get);                         // Stack: ... name => value
                    }
                }
            }
            else if (state.IsOp("("))
            {
                state.Advance();

                ParseExpression(state);

                state.Advance(")");
            }
            else
            {
                throw SyntaxError(
                          state.Position,
                          "Expected a number, a string, a name, or '(', but got '{0}'",
                          state.Value);
            }
        }
Esempio n. 26
0
        public override IMatched <Unit> ParseStatement(ParseState state, Token[] tokens)
        {
            var className     = tokens[3].Text;
            var hasParameters = tokens[4].Text == "(";

            state.Colorize(tokens, Color.Keyword, Color.Whitespace, Color.Class, Color.OpenParenthesis);

            Parameters parameters;

            if (hasParameters)
            {
                if (getParameters(state).ValueOrCast <Unit>(out parameters, out var asUnit))
                {
                }
                else if (asUnit.IsNotMatched)
                {
                    parameters = new Parameters(0);
                }
                else
                {
                    return(asUnit);
                }
            }
            else
            {
                parameters = Parameters.Empty;
            }

            state.SkipEndOfLine();

            state.Advance();
            var parentClassParser = new ParentClassParser();

            var parentClassName = "";
            var initialize      = false;
            var arguments       = new Expression[0];

            if (parentClassParser.Scan(state).If(out _, out var anyException))
            {
                (parentClassName, initialize, arguments) = parentClassParser.Parent;
            }
            else if (anyException.If(out var exception))
            {
                state.Regress();
                return(failedMatch <Unit>(exception));
            }

            var mixins = new List <Mixin>();

            while (state.More)
            {
                var mixinIncludesParser = new MixinIncludesParser(mixins);
                if (mixinIncludesParser.Scan(state).If(out _, out anyException))
                {
                }
                else if (anyException.If(out var exception))
                {
                    state.Regress();
                    return(failedMatch <Unit>(exception));
                }
                else
                {
                    break;
                }
            }

            state.SkipEndOfLine();
            state.Regress();

            Module.Global.ForwardReference(className);

            state.SkipEndOfLine();
            if (getBlock(state).ValueOrCast <Unit>(out var block, out var asUnit2))
            {
                var builder = new ClassBuilder(className, parameters, parentClassName, arguments, initialize, block, mixins);
                if (builder.Register().ValueOrOriginal(out _, out asUnit2))
                {
                    var cls = new Class(builder);
                    state.AddStatement(cls);

                    var classItemsParser = new ClassItemsParser(builder);
                    while (state.More)
                    {
                        if (classItemsParser.Scan(state).If(out _, out anyException))
                        {
                        }
                        else if (anyException.If(out var exception))
                        {
                            return(failedMatch <Unit>(exception));
                        }
                        else
                        {
                            break;
                        }
                    }

                    return(Unit.Matched());
                }
                else
                {
                    return(asUnit2);
                }
            }
            else
            {
                return(asUnit2);
            }
        }