Beispiel #1
0
        public TopLevelConstruct ParseTopLevel(
            TokenStream tokens,
            TopLevelConstruct owner,
            FileScope fileScope)
        {
            string value = tokens.PeekValue();

            Token staticToken = null;
            Token finalToken  = null;

            while (value == this.parser.Keywords.STATIC || value == this.parser.Keywords.FINAL)
            {
                if (value == this.parser.Keywords.STATIC && staticToken == null)
                {
                    staticToken = tokens.Pop();
                    value       = tokens.PeekValue();
                }
                if (value == this.parser.Keywords.FINAL && finalToken == null)
                {
                    finalToken = tokens.Pop();
                    value      = tokens.PeekValue();
                }
            }

            if (staticToken != null || finalToken != null)
            {
                if (value != this.parser.Keywords.CLASS)
                {
                    if (staticToken != null)
                    {
                        throw new ParserException(staticToken, "Only classes, methods, and fields may be marked as static");
                    }
                    else
                    {
                        throw new ParserException(finalToken, "Only classes may be marked as final.");
                    }
                }

                if (staticToken != null && finalToken != null)
                {
                    throw new ParserException(staticToken, "Classes cannot be both static and final.");
                }
            }

            if (value == parser.Keywords.IMPORT)
            {
                Token         importToken       = tokens.PopExpected(parser.Keywords.IMPORT);
                List <string> importPathBuilder = new List <string>();
                while (!tokens.PopIfPresent(";"))
                {
                    if (importPathBuilder.Count > 0)
                    {
                        tokens.PopExpected(".");
                    }

                    Token pathToken = tokens.Pop();
                    parser.VerifyIdentifier(pathToken);
                    importPathBuilder.Add(pathToken.Value);
                }
                string importPath = string.Join(".", importPathBuilder);

                return(new ImportStatement(importToken, importPath, parser.CurrentLibrary, fileScope));
            }

            if (value == this.parser.Keywords.ENUM)
            {
                return(this.ParseEnumDefinition(tokens, owner, fileScope));
            }

            if (value == this.parser.Keywords.NAMESPACE)
            {
                return(this.ParseNamespace(tokens, owner, fileScope));
            }

            if (value == this.parser.Keywords.CONST)
            {
                return(this.ParseConst(tokens, owner, fileScope));
            }
            if (value == this.parser.Keywords.FUNCTION)
            {
                return(this.ParseFunction(tokens, owner, fileScope));
            }
            if (value == this.parser.Keywords.CLASS)
            {
                return(this.ParseClassDefinition(tokens, owner, staticToken, finalToken, fileScope));
            }
            if (value == this.parser.Keywords.ENUM)
            {
                return(this.ParseEnumDefinition(tokens, owner, fileScope));
            }
            if (value == this.parser.Keywords.CONSTRUCTOR)
            {
                return(this.ParseConstructor(tokens, owner));
            }

            throw new ParserException(tokens.Peek(), "Unrecognized token.");
        }
Beispiel #2
0
        private Executable ParseSwitch(TokenStream tokens, TopLevelConstruct owner)
        {
            Token switchToken = tokens.PopExpected(this.parser.Keywords.SWITCH);

            Expression explicitMax      = null;
            Token      explicitMaxToken = null;

            if (tokens.IsNext("{"))
            {
                explicitMaxToken = tokens.Pop();
                explicitMax      = this.parser.ExpressionParser.Parse(tokens, owner);
                tokens.PopExpected("}");
            }

            tokens.PopExpected("(");
            Expression condition = this.parser.ExpressionParser.Parse(tokens, owner);

            tokens.PopExpected(")");
            tokens.PopExpected("{");
            List <List <Expression> > cases = new List <List <Expression> >();
            List <Token> firstTokens        = new List <Token>();
            List <List <Executable> > code  = new List <List <Executable> >();
            char state = '?'; // ? - first, O - code, A - case
            bool defaultEncountered = false;

            while (!tokens.PopIfPresent("}"))
            {
                if (tokens.IsNext(this.parser.Keywords.CASE))
                {
                    if (defaultEncountered)
                    {
                        throw new ParserException(tokens.Peek(), "default condition in a switch statement must be the last condition.");
                    }

                    Token caseToken = tokens.PopExpected(this.parser.Keywords.CASE);
                    if (state != 'A')
                    {
                        cases.Add(new List <Expression>());
                        firstTokens.Add(caseToken);
                        code.Add(null);
                        state = 'A';
                    }
                    cases[cases.Count - 1].Add(this.parser.ExpressionParser.Parse(tokens, owner));
                    tokens.PopExpected(":");
                }
                else if (tokens.IsNext(this.parser.Keywords.DEFAULT))
                {
                    Token defaultToken = tokens.PopExpected(this.parser.Keywords.DEFAULT);
                    if (state != 'A')
                    {
                        cases.Add(new List <Expression>());
                        firstTokens.Add(defaultToken);
                        code.Add(null);
                        state = 'A';
                    }
                    cases[cases.Count - 1].Add(null);
                    tokens.PopExpected(":");
                    defaultEncountered = true;
                }
                else
                {
                    if (state != 'O')
                    {
                        cases.Add(null);
                        firstTokens.Add(null);
                        code.Add(new List <Executable>());
                        state = 'O';
                    }
                    code[code.Count - 1].Add(this.parser.ExecutableParser.Parse(tokens, false, true, owner));
                }
            }

            return(new SwitchStatement(switchToken, condition, firstTokens, cases, code, explicitMax, explicitMaxToken, owner));
        }
Beispiel #3
0
        private static Expression ParseEntityWithoutSuffixChain(TokenStream tokens, Executable owner)
        {
            string next = tokens.PeekValue();

            if (next == "null")
            {
                return(new NullConstant(tokens.Pop(), owner));
            }
            if (next == "true")
            {
                return(new BooleanConstant(tokens.Pop(), true, owner));
            }
            if (next == "false")
            {
                return(new BooleanConstant(tokens.Pop(), false, owner));
            }

            Token peekToken = tokens.Peek();

            if (next.StartsWith("'"))
            {
                return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner));
            }
            if (next.StartsWith("\""))
            {
                return(new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner));
            }
            if (next == "new")
            {
                return(ParseInstantiate(tokens, owner));
            }

            char firstChar = next[0];

            if (VARIABLE_STARTER.Contains(firstChar))
            {
                Token varToken = tokens.Pop();
                return(new Variable(varToken, varToken.Value, owner));
            }

            if (firstChar == '[')
            {
                Token             bracketToken = tokens.PopExpected("[");
                List <Expression> elements     = new List <Expression>();
                bool previousHasCommaOrFirst   = true;
                while (!tokens.PopIfPresent("]"))
                {
                    if (!previousHasCommaOrFirst)
                    {
                        tokens.PopExpected("]");                           // throws appropriate error
                    }
                    elements.Add(Parse(tokens, owner));
                    previousHasCommaOrFirst = tokens.PopIfPresent(",");
                }
                return(new ListDefinition(bracketToken, elements, owner));
            }

            if (firstChar == '{')
            {
                Token             braceToken = tokens.PopExpected("{");
                List <Expression> keys       = new List <Expression>();
                List <Expression> values     = new List <Expression>();
                bool previousHasCommaOrFirst = true;
                while (!tokens.PopIfPresent("}"))
                {
                    if (!previousHasCommaOrFirst)
                    {
                        tokens.PopExpected("}");                           // throws appropriate error
                    }
                    keys.Add(Parse(tokens, owner));
                    tokens.PopExpected(":");
                    values.Add(Parse(tokens, owner));
                    previousHasCommaOrFirst = tokens.PopIfPresent(",");
                }
                return(new DictionaryDefinition(braceToken, keys, values, owner));
            }

            if (next.Length > 2 && next.Substring(0, 2) == "0x")
            {
                Token intToken = tokens.Pop();
                int   intValue = IntegerConstant.ParseIntConstant(intToken, intToken.Value);
                return(new IntegerConstant(intToken, intValue, owner));
            }

            if (Parser.IsInteger(next))
            {
                Token  numberToken = tokens.Pop();
                string numberValue = numberToken.Value;

                if (tokens.IsNext("."))
                {
                    Token decimalToken = tokens.Pop();
                    if (decimalToken.HasWhitespacePrefix)
                    {
                        throw new ParserException(decimalToken, "Decimals cannot have whitespace before them.");
                    }

                    Token afterDecimal = tokens.Pop();
                    if (afterDecimal.HasWhitespacePrefix)
                    {
                        throw new ParserException(afterDecimal, "Cannot have whitespace after the decimal.");
                    }
                    if (!Parser.IsInteger(afterDecimal.Value))
                    {
                        throw new ParserException(afterDecimal, "Decimal must be followed by an integer.");
                    }

                    numberValue += "." + afterDecimal.Value;

                    double floatValue = FloatConstant.ParseValue(numberToken, numberValue);
                    return(new FloatConstant(numberToken, floatValue, owner));
                }

                int intValue = IntegerConstant.ParseIntConstant(numberToken, numberToken.Value);
                return(new IntegerConstant(numberToken, intValue, owner));
            }

            if (tokens.IsNext("."))
            {
                Token  dotToken    = tokens.PopExpected(".");
                string numberValue = "0.";
                Token  postDecimal = tokens.Pop();
                if (postDecimal.HasWhitespacePrefix || !Parser.IsInteger(postDecimal.Value))
                {
                    throw new ParserException(dotToken, "Unexpected dot.");
                }

                numberValue += postDecimal.Value;

                double floatValue;
                if (double.TryParse(numberValue, out floatValue))
                {
                    return(new FloatConstant(dotToken, floatValue, owner));
                }

                throw new ParserException(dotToken, "Invalid float literal.");
            }

            throw new ParserException(tokens.Peek(), "Encountered unexpected token: '" + tokens.PeekValue() + "'");
        }
Beispiel #4
0
        public Executable Parse(
            TokenStream tokens,
            bool simpleOnly,
            bool semicolonPresent,
            TopLevelConstruct owner)
        {
            string value = tokens.PeekValue();

            if (!simpleOnly)
            {
                if (value == this.parser.Keywords.FUNCTION || value == this.parser.Keywords.CLASS)
                {
                    throw new ParserException(
                              tokens.Peek(),
                              (value == this.parser.Keywords.FUNCTION ? "Function" : "Class") +
                              " definition cannot be nested in another construct.");
                }

                if (value == parser.Keywords.IMPORT)
                {
                    throw new ParserException(tokens.Peek(), "Imports can only be made from the root of a file and cannot be nested inside other constructs.");
                }

                if (value == this.parser.Keywords.ENUM)
                {
                    throw new ParserException(tokens.Peek(), "Enums can only be defined from the root of a file and cannot be nested inside functions/loops/etc.");
                }

                if (value == this.parser.Keywords.NAMESPACE)
                {
                    throw new ParserException(tokens.Peek(), "Namespace declarations cannot be nested in other constructs.");
                }

                if (value == this.parser.Keywords.CONST)
                {
                    throw new ParserException(tokens.Peek(), "Constant declarations cannot be nested in other constructs.");
                }

                if (value == this.parser.Keywords.FOR)
                {
                    return(this.ParseFor(tokens, owner));
                }
                if (value == this.parser.Keywords.WHILE)
                {
                    return(this.ParseWhile(tokens, owner));
                }
                if (value == this.parser.Keywords.DO)
                {
                    return(this.ParseDoWhile(tokens, owner));
                }
                if (value == this.parser.Keywords.SWITCH)
                {
                    return(this.ParseSwitch(tokens, owner));
                }
                if (value == this.parser.Keywords.IF)
                {
                    return(this.ParseIf(tokens, owner));
                }
                if (value == this.parser.Keywords.TRY)
                {
                    return(this.ParseTry(tokens, owner));
                }
                if (value == this.parser.Keywords.RETURN)
                {
                    return(this.ParseReturn(tokens, owner));
                }
                if (value == this.parser.Keywords.BREAK)
                {
                    return(this.ParseBreak(tokens, owner));
                }
                if (value == this.parser.Keywords.CONTINUE)
                {
                    return(this.ParseContinue(tokens, owner));
                }
                if (value == this.parser.Keywords.THROW)
                {
                    return(this.ParseThrow(tokens, owner));
                }
            }

            Expression expr = this.parser.ExpressionParser.Parse(tokens, owner);

            value = tokens.PeekValue();
            if (ASSIGNMENT_OPS.Contains(value))
            {
                Token      assignment      = tokens.Pop();
                Expression assignmentValue = this.parser.ExpressionParser.Parse(tokens, owner);
                if (semicolonPresent)
                {
                    tokens.PopExpected(";");
                }
                return(new Assignment(expr, assignment, assignment.Value, assignmentValue, owner));
            }

            if (semicolonPresent)
            {
                tokens.PopExpected(";");
            }

            return(new ExpressionAsExecutable(expr, owner));
        }
Beispiel #5
0
        public Executable Parse(
            TokenStream tokens,
            bool simpleOnly,
            bool semicolonPresent,
            bool isRoot,
            Executable owner)
        {
            string value = tokens.PeekValue();

            if (!simpleOnly)
            {
                Token staticToken = null;
                Token finalToken  = null;
                while (value == this.parser.Keywords.STATIC || value == this.parser.Keywords.FINAL)
                {
                    if (value == this.parser.Keywords.STATIC && staticToken == null)
                    {
                        staticToken = tokens.Pop();
                        value       = tokens.PeekValue();
                    }
                    if (value == this.parser.Keywords.FINAL && finalToken == null)
                    {
                        finalToken = tokens.Pop();
                        value      = tokens.PeekValue();
                    }
                }

                if (staticToken != null || finalToken != null)
                {
                    if (value != this.parser.Keywords.CLASS)
                    {
                        if (staticToken != null)
                        {
                            throw new ParserException(staticToken, "Only classes, methods, and fields may be marked as static");
                        }
                        else
                        {
                            throw new ParserException(finalToken, "Only classes may be marked as final.");
                        }
                    }

                    if (staticToken != null && finalToken != null)
                    {
                        throw new ParserException(staticToken, "Classes cannot be both static and final.");
                    }
                }

                if (!isRoot &&
                    (value == this.parser.Keywords.FUNCTION || value == this.parser.Keywords.CLASS))
                {
                    throw new ParserException(
                              tokens.Peek(),
                              (value == this.parser.Keywords.FUNCTION ? "Function" : "Class") +
                              " definition cannot be nested in another construct.");
                }


                if (value == parser.Keywords.IMPORT)
                {
                    Token importToken = tokens.PopExpected(parser.Keywords.IMPORT);

                    if (!isRoot)
                    {
                        throw new ParserException(tokens.Peek(), "Imports can only be made from the root of a file and cannot be nested inside other constructs.");
                    }

                    List <string> importPathBuilder = new List <string>();
                    while (!tokens.PopIfPresent(";"))
                    {
                        if (importPathBuilder.Count > 0)
                        {
                            tokens.PopExpected(".");
                        }

                        Token pathToken = tokens.Pop();
                        parser.VerifyIdentifier(pathToken);
                        importPathBuilder.Add(pathToken.Value);
                    }
                    string importPath = string.Join(".", importPathBuilder);

                    return(new ImportStatement(importToken, importPath));
                }

                if (value == this.parser.Keywords.ENUM)
                {
                    if (!isRoot)
                    {
                        throw new ParserException(tokens.Peek(), "Enums can only be defined from the root of a file and cannot be nested inside functions/loops/etc.");
                    }

                    return(this.ParseEnumDefinition(tokens, owner));
                }

                if (value == this.parser.Keywords.NAMESPACE)
                {
                    if (!isRoot)
                    {
                        throw new ParserException(tokens.Peek(), "Namespace declarations cannot be nested in other constructs.");
                    }
                    return(this.ParseNamespace(tokens, owner));
                }

                if (value == this.parser.Keywords.CONST)
                {
                    return(this.ParseConst(tokens, owner));
                }
                if (value == this.parser.Keywords.FUNCTION)
                {
                    return(this.ParseFunction(tokens, owner));
                }
                if (value == this.parser.Keywords.CLASS)
                {
                    return(this.ParseClassDefinition(tokens, owner, staticToken, finalToken));
                }
                if (value == this.parser.Keywords.ENUM)
                {
                    return(this.ParseEnumDefinition(tokens, owner));
                }
                if (value == this.parser.Keywords.FOR)
                {
                    return(this.ParseFor(tokens, owner));
                }
                if (value == this.parser.Keywords.WHILE)
                {
                    return(this.ParseWhile(tokens, owner));
                }
                if (value == this.parser.Keywords.DO)
                {
                    return(this.ParseDoWhile(tokens, owner));
                }
                if (value == this.parser.Keywords.SWITCH)
                {
                    return(this.ParseSwitch(tokens, owner));
                }
                if (value == this.parser.Keywords.IF)
                {
                    return(this.ParseIf(tokens, owner));
                }
                if (value == this.parser.Keywords.TRY)
                {
                    return(this.ParseTry(tokens, owner));
                }
                if (value == this.parser.Keywords.RETURN)
                {
                    return(this.ParseReturn(tokens, owner));
                }
                if (value == this.parser.Keywords.BREAK)
                {
                    return(this.ParseBreak(tokens, owner));
                }
                if (value == this.parser.Keywords.CONTINUE)
                {
                    return(this.ParseContinue(tokens, owner));
                }
                if (value == this.parser.Keywords.CONSTRUCTOR)
                {
                    return(this.ParseConstructor(tokens, owner));
                }
                if (value == this.parser.Keywords.THROW)
                {
                    return(this.ParseThrow(tokens, owner));
                }
            }

            Expression expr = this.parser.ExpressionParser.Parse(tokens, owner);

            value = tokens.PeekValue();
            if (ASSIGNMENT_OPS.Contains(value))
            {
                Token      assignment      = tokens.Pop();
                Expression assignmentValue = this.parser.ExpressionParser.Parse(tokens, owner);
                if (semicolonPresent)
                {
                    tokens.PopExpected(";");
                }
                return(new Assignment(expr, assignment, assignment.Value, assignmentValue, owner));
            }

            if (semicolonPresent)
            {
                tokens.PopExpected(";");
            }

            return(new ExpressionAsExecutable(expr, owner));
        }
Beispiel #6
0
		private static Executable ParseSwitch(Parser parser, TokenStream tokens, Executable owner)
		{
			Token switchToken = tokens.PopExpected("switch");

			Expression explicitMax = null;
			Token explicitMaxToken = null;
			if (tokens.IsNext("{"))
			{
				explicitMaxToken = tokens.Pop();
				explicitMax = ExpressionParser.Parse(tokens, owner);
				tokens.PopExpected("}");
			}

			tokens.PopExpected("(");
			Expression condition = ExpressionParser.Parse(tokens, owner);
			tokens.PopExpected(")");
			tokens.PopExpected("{");
			List<List<Expression>> cases = new List<List<Expression>>();
			List<Token> firstTokens = new List<Token>();
			List<List<Executable>> code = new List<List<Executable>>();
			char state = '?'; // ? - first, O - code, A - case
			bool defaultEncountered = false;
			while (!tokens.PopIfPresent("}"))
			{
				if (tokens.IsNext("case"))
				{
					if (defaultEncountered)
					{
						throw new ParserException(tokens.Peek(), "default condition in a switch statement must be the last condition.");
					}

					Token caseToken = tokens.PopExpected("case");
					if (state != 'A')
					{
						cases.Add(new List<Expression>());
						firstTokens.Add(caseToken);
						code.Add(null);
						state = 'A';
					}
					cases[cases.Count - 1].Add(ExpressionParser.Parse(tokens, owner));
					tokens.PopExpected(":");
				}
				else if (tokens.IsNext("default"))
				{
					Token defaultToken = tokens.PopExpected("default");
					if (state != 'A')
					{
						cases.Add(new List<Expression>());
						firstTokens.Add(defaultToken);
						code.Add(null);
						state = 'A';
					}
					cases[cases.Count - 1].Add(null);
					tokens.PopExpected(":");
					defaultEncountered = true;
				}
				else
				{
					if (state != 'O')
					{
						cases.Add(null);
						firstTokens.Add(null);
						code.Add(new List<Executable>());
						state = 'O';
					}
					code[code.Count - 1].Add(ExecutableParser.Parse(parser, tokens, false, true, false, owner));
				}
			}

			return new SwitchStatement(switchToken, condition, firstTokens, cases, code, explicitMax, explicitMaxToken, owner);
		}
Beispiel #7
0
		public static Executable Parse(Parser parser, TokenStream tokens, bool simpleOnly, bool semicolonPresent, bool isRoot, Executable owner)
		{
			string value = tokens.PeekValue();

			if (!simpleOnly)
			{
				if (parser.IsTranslateMode && value == "struct")
				{
					if (!isRoot)
					{
						throw new ParserException(tokens.Peek(), "structs cannot be nested into any other construct.");
					}

					// struct is special. If you are not compiling in JS mode, 
					if (Parser.IsValidIdentifier(tokens.PeekValue(1)) && tokens.PeekValue(2) == "{")
					{
						return ParseStruct(tokens, owner);
					}
				}

				if (!isRoot && (value == "function" || value == "class"))
				{
					throw new ParserException(tokens.Peek(), (value == "function" ? "Function" : "Class") + " definition cannot be nested in another construct.");
				}

				if (value == "import")
				{
					Token importToken = tokens.PopExpected("import");

					bool inline = parser.IsTranslateMode && tokens.PopIfPresent("inline");

					if (inline)
					{
						Token fileToken = tokens.Pop();
						char c = fileToken.Value[0];
						if (c != '\'' && c != '"') throw new ParserException(fileToken, "Inline imports are supposed to be strings.");
						tokens.PopExpected(";");
						string inlineImportFileName = fileToken.Value.Substring(1, fileToken.Value.Length - 2);
						string inlineImportFileContents = Util.ReadFileInternally(inlineImportFileName);
						// TODO: Anti-pattern alert. Clean this up.
						if (inlineImportFileContents.Contains("%%%"))
						{
							Dictionary<string, string> replacements = parser.NullablePlatform.InterpreterCompiler.BuildReplacementsDictionary();
							inlineImportFileContents = Constants.DoReplacements(inlineImportFileContents, replacements);
						}
						TokenStream inlineTokens = Tokenizer.Tokenize(inlineImportFileName, inlineImportFileContents, 0, true);

						// OMGHAX - insert the inline import into the current token stream.
						tokens.InsertTokens(inlineTokens);

						return ExecutableParser.Parse(parser, tokens, simpleOnly, semicolonPresent, isRoot, owner); // start exectuable parser anew.
					}

					if (!isRoot)
					{
						throw new ParserException(tokens.Peek(), "Imports can only be made from the root of a file and cannot be nested inside other constructs.");
					}

					List<string> importPathBuilder = new List<string>();
					while (!tokens.PopIfPresent(";"))
					{
						if (importPathBuilder.Count > 0)
						{
							tokens.PopExpected(".");
						}

						Token pathToken = tokens.Pop();
						Parser.VerifyIdentifier(pathToken);
						importPathBuilder.Add(pathToken.Value);
					}
					string importPath = string.Join(".", importPathBuilder);

					return new ImportStatement(importToken, importPath);
				}

				if (value == "enum")
				{
					if (!isRoot)
					{
						throw new ParserException(tokens.Peek(), "Enums can only be defined from the root of a file and cannot be nested inside functions/loops/etc.");
					}

					return ParseEnumDefinition(parser, tokens, owner);
				}

				if (value == "namespace")
				{
					if (!isRoot)
					{
						throw new ParserException(tokens.Peek(), "Namespace declarations cannot be nested in other constructs.");
					}
				}

				switch (value)
				{
					case "namespace": return ParseNamespace(parser, tokens, owner);
					case "function": return ParseFunction(parser, tokens, owner);
					case "class": return ParseClassDefinition(parser, tokens, owner);
					case "enum": return ParseEnumDefinition(parser, tokens, owner);
					case "for": return ParseFor(parser, tokens, owner);
					case "while": return ParseWhile(parser, tokens, owner);
					case "do": return ParseDoWhile(parser, tokens, owner);
					case "switch": return ParseSwitch(parser, tokens, owner);
					case "if": return ParseIf(parser, tokens, owner);
					case "try": return ParseTry(parser, tokens, owner);
					case "return": return ParseReturn(tokens, owner);
					case "break": return ParseBreak(tokens, owner);
					case "continue": return ParseContinue(tokens, owner);
					case "const": return ParseConst(parser, tokens, owner);
					case "constructor": return ParseConstructor(parser, tokens, owner);
					default: break;
				}
			}

			Expression expr = ExpressionParser.Parse(tokens, owner);
			value = tokens.PeekValue();
			if (ASSIGNMENT_OPS.Contains(value))
			{
				Token assignment = tokens.Pop();
				Expression assignmentValue = ExpressionParser.Parse(tokens, owner);
				if (semicolonPresent) tokens.PopExpected(";");
				return new Assignment(expr, assignment, assignment.Value, assignmentValue, owner);
			}

			if (semicolonPresent)
			{
				tokens.PopExpected(";");
			}

			return new ExpressionAsExecutable(expr, owner);
		}
Beispiel #8
0
        public static Executable Parse(Parser parser, TokenStream tokens, bool simpleOnly, bool semicolonPresent, bool isRoot, Executable owner)
        {
            string value = tokens.PeekValue();

            if (!simpleOnly)
            {
                Token staticToken = null;
                Token finalToken  = null;
                while (value == "static" || value == "final")
                {
                    if (value == "static" && staticToken == null)
                    {
                        staticToken = tokens.Pop();
                        value       = tokens.PeekValue();
                    }
                    if (value == "final" && finalToken == null)
                    {
                        finalToken = tokens.Pop();
                        value      = tokens.PeekValue();
                    }
                }

                if (staticToken != null || finalToken != null)
                {
                    if (value != "class")
                    {
                        if (staticToken != null)
                        {
                            throw new ParserException(staticToken, "Only classes, methods, and fields may be marked as static");
                        }
                        else
                        {
                            throw new ParserException(finalToken, "Only classes may be marked as final.");
                        }
                    }

                    if (staticToken != null && finalToken != null)
                    {
                        throw new ParserException(staticToken, "Classes cannot be both static and final.");
                    }
                }

                if (!isRoot && (value == "function" || value == "class"))
                {
                    throw new ParserException(tokens.Peek(), (value == "function" ? "Function" : "Class") + " definition cannot be nested in another construct.");
                }

                if (parser.IsTranslateMode && value == "struct")
                {
                    if (!isRoot)
                    {
                        throw new ParserException(tokens.Peek(), "structs cannot be nested into any other construct.");
                    }

                    return(ParseStruct(tokens, owner));
                }

                if (value == "import")
                {
                    Token importToken = tokens.PopExpected("import");

                    bool inline = parser.IsTranslateMode && tokens.PopIfPresent("inline");

                    if (inline)
                    {
                        Token fileToken = tokens.Pop();
                        char  c         = fileToken.Value[0];
                        if (c != '\'' && c != '"')
                        {
                            throw new ParserException(fileToken, "Inline imports are supposed to be strings.");
                        }
                        tokens.PopExpected(";");
                        string inlineImportFileName = fileToken.Value.Substring(1, fileToken.Value.Length - 2);
                        string inlineImportFileContents;
                        if (inlineImportFileName.StartsWith("LIB:"))
                        {
                            string[] parts       = inlineImportFileName.Split(':');
                            string   libraryName = parts[1];
                            string   filename    = FileUtil.JoinPath(parts[2].Split('/'));
                            Library  library     = parser.SystemLibraryManager.GetLibraryFromKey(libraryName.ToLower());
                            inlineImportFileContents = library.ReadFile(filename, false);
                        }
                        else
                        {
                            inlineImportFileContents = Util.ReadInterpreterFileInternally(inlineImportFileName);
                        }
                        // TODO: Anti-pattern alert. Clean this up.
                        if (inlineImportFileContents.Contains("%%%"))
                        {
                            Dictionary <string, string> replacements = parser.NullablePlatform.InterpreterCompiler.BuildReplacementsDictionary();
                            inlineImportFileContents = Constants.DoReplacements(inlineImportFileContents, replacements);
                        }
                        Token[] inlineTokens = Tokenizer.Tokenize(inlineImportFileName, inlineImportFileContents, 0, true);

                        tokens.InsertTokens(inlineTokens);

                        return(ExecutableParser.Parse(parser, tokens, simpleOnly, semicolonPresent, isRoot, owner)); // start exectuable parser anew.
                    }

                    if (!isRoot)
                    {
                        throw new ParserException(tokens.Peek(), "Imports can only be made from the root of a file and cannot be nested inside other constructs.");
                    }

                    List <string> importPathBuilder = new List <string>();
                    while (!tokens.PopIfPresent(";"))
                    {
                        if (importPathBuilder.Count > 0)
                        {
                            tokens.PopExpected(".");
                        }

                        Token pathToken = tokens.Pop();
                        Parser.VerifyIdentifier(pathToken);
                        importPathBuilder.Add(pathToken.Value);
                    }
                    string importPath = string.Join(".", importPathBuilder);

                    return(new ImportStatement(importToken, importPath));
                }

                if (value == "enum")
                {
                    if (!isRoot)
                    {
                        throw new ParserException(tokens.Peek(), "Enums can only be defined from the root of a file and cannot be nested inside functions/loops/etc.");
                    }

                    return(ParseEnumDefinition(parser, tokens, owner));
                }

                if (value == "namespace")
                {
                    if (!isRoot)
                    {
                        throw new ParserException(tokens.Peek(), "Namespace declarations cannot be nested in other constructs.");
                    }
                }

                switch (value)
                {
                case "namespace": return(ParseNamespace(parser, tokens, owner));

                case "function": return(ParseFunction(parser, tokens, owner));

                case "class": return(ParseClassDefinition(parser, tokens, owner, staticToken, finalToken));

                case "enum": return(ParseEnumDefinition(parser, tokens, owner));

                case "for": return(ParseFor(parser, tokens, owner));

                case "while": return(ParseWhile(parser, tokens, owner));

                case "do": return(ParseDoWhile(parser, tokens, owner));

                case "switch": return(ParseSwitch(parser, tokens, owner));

                case "if": return(ParseIf(parser, tokens, owner));

                case "try": return(ParseTry(parser, tokens, owner));

                case "return": return(ParseReturn(tokens, owner));

                case "break": return(ParseBreak(tokens, owner));

                case "continue": return(ParseContinue(tokens, owner));

                case "const": return(ParseConst(parser, tokens, owner));

                case "constructor": return(ParseConstructor(parser, tokens, owner));

                default: break;
                }
            }

            Expression expr = ExpressionParser.Parse(tokens, owner);

            value = tokens.PeekValue();
            if (ASSIGNMENT_OPS.Contains(value))
            {
                Token      assignment      = tokens.Pop();
                Expression assignmentValue = ExpressionParser.Parse(tokens, owner);
                if (semicolonPresent)
                {
                    tokens.PopExpected(";");
                }
                return(new Assignment(expr, assignment, assignment.Value, assignmentValue, owner));
            }

            if (semicolonPresent)
            {
                tokens.PopExpected(";");
            }

            return(new ExpressionAsExecutable(expr, owner));
        }
Beispiel #9
0
		private static Expression ParseEntityWithoutSuffixChain(TokenStream tokens, Executable owner)
		{
			string next = tokens.PeekValue();

			if (next == "null") return new NullConstant(tokens.Pop(), owner);
			if (next == "true") return new BooleanConstant(tokens.Pop(), true, owner);
			if (next == "false") return new BooleanConstant(tokens.Pop(), false, owner);

			Token peekToken = tokens.Peek();
			if (next.StartsWith("'")) return new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner);
			if (next.StartsWith("\"")) return new StringConstant(tokens.Pop(), StringConstant.ParseOutRawValue(peekToken), owner);
			if (next == "new") return ParseInstantiate(tokens, owner);

			char firstChar = next[0];
			if (VARIABLE_STARTER.Contains(firstChar))
			{
				Token varToken = tokens.Pop();
				return new Variable(varToken, varToken.Value, owner);
			}

			if (firstChar == '[')
			{
				Token bracketToken = tokens.PopExpected("[");
				List<Expression> elements = new List<Expression>();
				bool previousHasCommaOrFirst = true;
				while (!tokens.PopIfPresent("]"))
				{
					if (!previousHasCommaOrFirst) tokens.PopExpected("]"); // throws appropriate error
					elements.Add(Parse(tokens, owner));
					previousHasCommaOrFirst = tokens.PopIfPresent(",");
				}
				return new ListDefinition(bracketToken, elements, owner);
			}

			if (firstChar == '{')
			{
				Token braceToken = tokens.PopExpected("{");
				List<Expression> keys = new List<Expression>();
				List<Expression> values = new List<Expression>();
				bool previousHasCommaOrFirst = true;
				while (!tokens.PopIfPresent("}"))
				{
					if (!previousHasCommaOrFirst) tokens.PopExpected("}"); // throws appropriate error
					keys.Add(Parse(tokens, owner));
					tokens.PopExpected(":");
					values.Add(Parse(tokens, owner));
					previousHasCommaOrFirst = tokens.PopIfPresent(",");
				}
				return new DictionaryDefinition(braceToken, keys, values, owner);
			}

			if (next.Length > 2 && next.Substring(0, 2) == "0x")
			{
				Token intToken = tokens.Pop();
				int intValue = IntegerConstant.ParseIntConstant(intToken, intToken.Value);
				return new IntegerConstant(intToken, intValue, owner);
			}

			if (Parser.IsInteger(next))
			{
				Token numberToken = tokens.Pop();
				string numberValue = numberToken.Value;

				if (tokens.IsNext("."))
				{
					Token decimalToken = tokens.Pop();
					if (decimalToken.HasWhitespacePrefix)
					{
						throw new ParserException(decimalToken, "Decimals cannot have whitespace before them.");
					}

					Token afterDecimal = tokens.Pop();
					if (afterDecimal.HasWhitespacePrefix) throw new ParserException(afterDecimal, "Cannot have whitespace after the decimal.");
					if (!Parser.IsInteger(afterDecimal.Value)) throw new ParserException(afterDecimal, "Decimal must be followed by an integer.");

					numberValue += "." + afterDecimal.Value;

					double floatValue = FloatConstant.ParseValue(numberToken, numberValue);
					return new FloatConstant(numberToken, floatValue, owner);
				}

				int intValue = IntegerConstant.ParseIntConstant(numberToken, numberToken.Value);
				return new IntegerConstant(numberToken, intValue, owner);
			}

			if (tokens.IsNext("."))
			{
				Token dotToken = tokens.PopExpected(".");
				string numberValue = "0.";
				Token postDecimal = tokens.Pop();
				if (postDecimal.HasWhitespacePrefix || !Parser.IsInteger(postDecimal.Value))
				{
					throw new ParserException(dotToken, "Unexpected dot.");
				}

				numberValue += postDecimal.Value;

				double floatValue;
				if (double.TryParse(numberValue, out floatValue))
				{
					return new FloatConstant(dotToken, floatValue, owner);
				}

				throw new ParserException(dotToken, "Invalid float literal.");
			}

			throw new ParserException(tokens.Peek(), "Encountered unexpected token: '" + tokens.PeekValue() + "'");
		}