Exemplo n.º 1
0
    public void ParseRgbColorProperty()
    {
        var nodes = StyleParser.Parse(@"
            style withBg {
                BackgroundColor = rgb(10, 20, 30);
            }
        ");

        Assert.AreEqual(1, nodes.Count);
        var rootNode = ((StyleRootNode)nodes[0]);

        Assert.AreEqual("withBg", rootNode.identifier);
        Assert.AreEqual(null, rootNode.tagName);
        Assert.AreEqual(1, rootNode.children.Count);

        var property = (((PropertyNode)rootNode.children[0]));

        Assert.AreEqual("BackgroundColor", property.identifier);
        Assert.AreEqual(StyleASTNodeType.Rgb, property.children[0].type);

        var rgbNode = (RgbNode)property.children[0];

        Assert.AreEqual(StyleASTNodeType.Rgb, rgbNode.type);
        Assert.AreEqual(StyleASTNodeFactory.NumericLiteralNode("10"), rgbNode.red);
        Assert.AreEqual(StyleASTNodeFactory.NumericLiteralNode("20"), rgbNode.green);
        Assert.AreEqual(StyleASTNodeFactory.NumericLiteralNode("30"), rgbNode.blue);
    }
Exemplo n.º 2
0
        private void ParseAnimationKeyFrames(AnimationRootNode rootNode)
        {
            while (tokenStream.HasMoreTokens && !AdvanceIfTokenType(StyleTokenType.BracesClose))
            {
                string value = AssertTokenTypeAndAdvance(StyleTokenType.Number);
                AssertTokenTypeAndAdvance(StyleTokenType.Mod);

                KeyFrameNode keyFrameNode = StyleASTNodeFactory.KeyFrameNode(int.Parse(value));

                while (AdvanceIfTokenType(StyleTokenType.Comma))
                {
                    keyFrameNode.keyframes.Add(int.Parse(AssertTokenTypeAndAdvance(StyleTokenType.Number)));
                    AssertTokenTypeAndAdvance(StyleTokenType.Mod);
                }

                AssertTokenTypeAndAdvance(StyleTokenType.BracesOpen);

                while (tokenStream.HasMoreTokens && !AdvanceIfTokenType(StyleTokenType.BracesClose))
                {
                    ParseProperties(keyFrameNode);
                }

                rootNode.AddKeyFrameNode(keyFrameNode);
            }
        }
Exemplo n.º 3
0
        private void ParseStateOrAttributeGroup(StyleNodeContainer styleRootNode)
        {
            switch (tokenStream.Current.styleTokenType)
            {
            // this is the state group
            case StyleTokenType.Identifier:
                StyleStateContainer stateGroupRootNode = StyleASTNodeFactory.StateGroupRootNode(tokenStream.Current);

                tokenStream.Advance();
                AssertTokenTypeAndAdvance(StyleTokenType.BracketClose);
                AssertTokenTypeAndAdvance(StyleTokenType.BracesOpen);

                ParseProperties(stateGroupRootNode);

                AssertTokenTypeAndAdvance(StyleTokenType.BracesClose);

                styleRootNode.AddChildNode(stateGroupRootNode);

                break;

            case StyleTokenType.AttributeSpecifier:
                ParseAttributeGroup();
                break;

            default:
                throw new ParseException(tokenStream.Current, "Expected either a group state identifier (hover etc.)" + " or an attribute identifier (attr:...)");
            }
        }
Exemplo n.º 4
0
        private StyleASTNode ParseIdentifierInParentheses()
        {
            AssertTokenTypeAndAdvance(StyleTokenType.ParenOpen);

            StyleASTNode identifier;

            switch (tokenStream.Current.styleTokenType)
            {
            case StyleTokenType.Identifier:
                identifier = StyleASTNodeFactory.IdentifierNode(tokenStream.Current.value);
                break;

            case StyleTokenType.At:
                identifier = ParseConstReference();
                break;

            default:
                throw new ParseException(tokenStream.Current, "Was expecting an identifier or a reference.");
            }

            tokenStream.Advance();
            // todo: add support for parameters here

            AssertTokenTypeAndAdvance(StyleTokenType.ParenClose);

            return(identifier);
        }
Exemplo n.º 5
0
        private RunNode ParseRunNode(RunCommandType cmdType, RunAction runAction)
        {
            StyleToken  runCommandToken = tokenStream.Current;
            CommandNode command;

            if (AdvanceIfTokenType(StyleTokenType.Animation))
            {
                command = StyleASTNodeFactory.AnimationCommandNode(ParseIdentifierInParentheses(), cmdType, runAction);
            }
            else if (AdvanceIfTokenType(StyleTokenType.Sound))
            {
                command = StyleASTNodeFactory.SoundCommandNode(ParseIdentifierInParentheses(), cmdType, runAction);
            }
            else
            {
                throw new ParseException(runCommandToken,
                                         $"Only animation and sound run commands are supported. Found {runCommandToken}");
            }

            command.WithLocation(tokenStream.Current);
            AssertTokenTypeAndAdvance(StyleTokenType.EndStatement);

            RunNode runNode = StyleASTNodeFactory.RunNode(command);

            runNode.WithLocation(runCommandToken);
            return(runNode);
        }
Exemplo n.º 6
0
    public void ParseUrl()
    {
        var nodes = StyleParser.Parse(@"
            style withBg {
                Background = url(path/to/image);
            }
        ");

        Assert.AreEqual(1, nodes.Count);
        var rootNode = ((StyleRootNode)nodes[0]);

        Assert.AreEqual("withBg", rootNode.identifier);
        Assert.AreEqual(null, rootNode.tagName);
        Assert.AreEqual(1, rootNode.children.Count);

        var property = (((PropertyNode)rootNode.children[0]));

        Assert.AreEqual("Background", property.identifier);
        Assert.AreEqual(StyleASTNodeType.Url, property.children[0].type);

        var urlNode = (UrlNode)property.children[0];

        Assert.AreEqual(StyleASTNodeType.Url, urlNode.type);
        Assert.AreEqual(StyleASTNodeFactory.IdentifierNode("path/to/image"), urlNode.url);
    }
Exemplo n.º 7
0
        private void ParseAttributeGroup()
        {
            AssertTokenTypeAndAdvance(StyleTokenType.AttributeSpecifier);
            AssertTokenTypeAndAdvance(StyleTokenType.Colon);
            StyleToken attributeToken      = tokenStream.Current;
            string     attributeIdentifier = AssertTokenTypeAndAdvance(StyleTokenType.Identifier);
            string     attributeValue      = null;

            if (AdvanceIfTokenType(StyleTokenType.EqualSign))
            {
                attributeValue = tokenStream.Current.value;
                tokenStream.Advance();
            }

            bool invert = groupOperatorStack.Count > 0 && groupOperatorStack.Pop() == StyleOperatorType.Not;

            AttributeNodeContainer andAttribute           = groupExpressionStack.Count > 0 ? groupExpressionStack.Pop() : null;
            AttributeNodeContainer attributeNodeContainer = StyleASTNodeFactory.AttributeGroupRootNode(attributeIdentifier, attributeValue, invert, andAttribute);

            attributeNodeContainer.WithLocation(attributeToken);

            groupExpressionStack.Push(attributeNodeContainer);

            AssertTokenTypeAndAdvance(StyleTokenType.BracketClose);
        }
Exemplo n.º 8
0
    public void CreateContextWithReferences()
    {
        LightList <StyleASTNode> nodes = new LightList <StyleASTNode>();

        nodes.Add(StyleASTNodeFactory.ExportNode(StyleASTNodeFactory.ConstNode("x", StyleASTNodeFactory.ConstReferenceNode("y"))));
        nodes.Add(StyleASTNodeFactory.ExportNode(StyleASTNodeFactory.ConstNode("y", StyleASTNodeFactory.ConstReferenceNode("z"))));
        var stringValue = StyleASTNodeFactory.StringLiteralNode("you win!");

        nodes.Add(StyleASTNodeFactory.ExportNode(StyleASTNodeFactory.ConstNode("z", stringValue)));

        var context = new StyleSheetConstantImporter(new StyleSheetImporter(null, null)).CreateContext(nodes, default);

        Assert.AreEqual(3, context.constants.Count);

        Assert.AreEqual("x", context.constants[2].name);
        Assert.AreEqual(stringValue, context.constants[2].value);
        Assert.True(context.constants[2].exported);

        Assert.AreEqual("y", context.constants[1].name);
        Assert.AreEqual(stringValue, context.constants[1].value);
        Assert.True(context.constants[1].exported);

        Assert.AreEqual("z", context.constants[0].name);
        Assert.AreEqual(stringValue, context.constants[0].value);
        Assert.True(context.constants[0].exported);

        Assert.AreEqual(0, context.constantsWithReferences.Count, "There should be no unresolved const left.");
    }
Exemplo n.º 9
0
        private StyleASTNode ParseLiteralOrReference(StyleTokenType literalType)
        {
            StyleToken currentToken = tokenStream.Current;

            if (AdvanceIfTokenType(StyleTokenType.At))
            {
                return(ParseConstReference().WithLocation(currentToken));
            }

            string value = AssertTokenTypeAndAdvance(literalType);

            switch (literalType)
            {
            case StyleTokenType.String:
                return(StyleASTNodeFactory.StringLiteralNode(value).WithLocation(currentToken));

            case StyleTokenType.Number:
                return(StyleASTNodeFactory.NumericLiteralNode(value).WithLocation(currentToken));

            case StyleTokenType.Boolean:
                return(StyleASTNodeFactory.BooleanLiteralNode(value).WithLocation(currentToken));

            case StyleTokenType.Identifier:
                return(StyleASTNodeFactory.IdentifierNode(value).WithLocation(currentToken));
            }

            throw new ParseException(currentToken, $"Please add support for this type: {literalType}!");
        }
Exemplo n.º 10
0
        private void ParseAnimationOptions(AnimationRootNode rootNode)
        {
            while (tokenStream.HasMoreTokens && !AdvanceIfTokenType(StyleTokenType.BracesClose))
            {
                StyleToken typeToken  = tokenStream.Current;
                string     optionName = AssertTokenTypeAndAdvance(StyleTokenType.Identifier).ToLower();
                bool       typeFound  = false;
                for (int index = 0; index < s_AnimationOptionNames.Length; index++)
                {
                    string name = s_AnimationOptionNames[index].Item1;
                    if (name == optionName)
                    {
                        AssertTokenTypeAndAdvance(StyleTokenType.EqualSign);
                        StyleToken variableToken = tokenStream.Current;

                        AnimationOptionNode optionNode = StyleASTNodeFactory.AnimationOptionNode(s_AnimationOptionNames[index].Item2, ParsePropertyValue());
                        optionNode.WithLocation(variableToken);

                        rootNode.AddOptionNode(optionNode);

                        typeFound = true;

                        break;
                    }
                }

                if (!typeFound)
                {
                    throw new ParseException(typeToken, $"{optionName} is not a supported animation option. Valid values are: {FormatOptionList(s_AnimationOptionNames)}\n");
                }

                AssertTokenTypeAndAdvance(StyleTokenType.EndStatement);
            }
        }
Exemplo n.º 11
0
        private void ParseExportNode()
        {
            StyleToken exportToken = tokenStream.Current;

            tokenStream.Advance();
            // export statement must be followed by const keyword

            // now let's find out which value we're assigning
            nodes.Add(StyleASTNodeFactory.ExportNode(ParseConstNode()).WithLocation(exportToken));
            AdvanceIfTokenType(StyleTokenType.EndStatement);
        }
Exemplo n.º 12
0
        private void ParseSpriteSheet()
        {
            StyleToken      initialStyleToken = tokenStream.Current;
            SpriteSheetNode rootNode          = StyleASTNodeFactory.SpriteSheetNode(initialStyleToken);

            rootNode.WithLocation(initialStyleToken);
            tokenStream.Advance();
            AssertTokenTypeAndAdvance(StyleTokenType.BracesOpen);
            SpriteSheetParseLoop(rootNode);
            nodes.Add(rootNode);
        }
Exemplo n.º 13
0
        private void ParseAnimation()
        {
            StyleToken        initialStyleToken = tokenStream.Current;
            AnimationRootNode animRoot          = StyleASTNodeFactory.AnimationRootNode(initialStyleToken);

            animRoot.WithLocation(initialStyleToken);
            tokenStream.Advance();
            AssertTokenTypeAndAdvance(StyleTokenType.BracesOpen);
            AnimationParseLoop(animRoot);
            nodes.Add(animRoot);
        }
Exemplo n.º 14
0
        private void ParseSound()
        {
            StyleToken    soundNameToken = tokenStream.Current;
            SoundRootNode soundRootNode  = StyleASTNodeFactory.SoundRootNode(soundNameToken);

            soundRootNode.WithLocation(soundNameToken);
            tokenStream.Advance();
            AssertTokenTypeAndAdvance(StyleTokenType.BracesOpen);
            SoundParseLoop(soundRootNode);
            nodes.Add(soundRootNode);
        }
Exemplo n.º 15
0
        private void ParseStyleExpression()
        {
            switch (tokenStream.Current.styleTokenType)
            {
            case StyleTokenType.Plus:
                StyleASTNodeFactory.OperatorNode(StyleOperatorType.Plus);
                break;
            }

            AssertTokenTypeAndAdvance(StyleTokenType.BracketClose);
        }
Exemplo n.º 16
0
        private StyleASTNode ParseConstReference()
        {
            AdvanceIfTokenType(StyleTokenType.At);
            ConstReferenceNode constReferenceNode = StyleASTNodeFactory.ConstReferenceNode(AssertTokenTypeAndAdvance(StyleTokenType.Identifier));

            while (tokenStream.HasMoreTokens && AdvanceIfTokenType(StyleTokenType.Dot))
            {
                constReferenceNode.AddChildNode(StyleASTNodeFactory.DotAccessNode(AssertTokenTypeAndAdvance(StyleTokenType.Identifier)).WithLocation(tokenStream.Previous));
            }

            return(constReferenceNode);
        }
Exemplo n.º 17
0
    public void ImportAndUseConsts()
    {
        LightList <StyleASTNode> nodes = new LightList <StyleASTNode>();

        nodes.Add(StyleASTNodeFactory.ImportNode("importedThing", "Data/Styles/ImportFromMe.style"));
        string basepath             = Path.Combine(Application.dataPath, "..", "Packages", "UIForia", "Tests");
        StyleCompileContext context = new StyleSheetConstantImporter(new StyleSheetImporter(basepath, null)).CreateContext(nodes, default);

        Assert.AreEqual(1, context.importedStyleConstants.Count);
        Assert.AreEqual(1, context.importedStyleConstants["importedThing"].Count);
        Assert.AreEqual("colorRed", context.importedStyleConstants["importedThing"][0].name);
    }
Exemplo n.º 18
0
    public void AssertAllStylePropertiesAreMapped() {
        foreach (var propId in Enum.GetValues(typeof(StylePropertyId))) {
            
            if (propId.ToString().StartsWith("__")) continue;
            
            var propertyNode = StyleASTNodeFactory.PropertyNode(propId.ToString());
            // this node should fail in a compile exception if this property is mapped.
            propertyNode.children.Add(new StyleRootNode());
            UIStyle target = new UIStyle();

            try {
                StylePropertyMappers.MapProperty(target, propertyNode, new StyleCompileContext(default));
Exemplo n.º 19
0
        private StyleASTNode ParseVariableReference()
        {
            AdvanceIfTokenType(StyleTokenType.Dollar);
            VariableReferenceNode refNode = new VariableReferenceNode(AssertTokenTypeAndAdvance(StyleTokenType.Identifier));

            while (tokenStream.HasMoreTokens && AdvanceIfTokenType(StyleTokenType.Dot))
            {
                refNode.AddChildNode(StyleASTNodeFactory.DotAccessNode(AssertTokenTypeAndAdvance(StyleTokenType.Identifier)).WithLocation(tokenStream.Previous));
            }

            return(refNode);
        }
Exemplo n.º 20
0
        /// <summary>
        /// Takes on all the things after a 'style' keyword on the root level of a style file.
        /// </summary>
        /// <exception cref="ParseException"></exception>
        private void ParseStyle()
        {
            string     identifier        = null;
            string     tagName           = null;
            StyleToken initialStyleToken = tokenStream.Current;

            switch (initialStyleToken.styleTokenType)
            {
            // <TagName> { ... }
            case StyleTokenType.LessThan:
                tokenStream.Advance();
                AssertTokenType(StyleTokenType.Identifier);
                tagName = tokenStream.Current.value;
                tokenStream.Advance();
                if (tokenStream.Current.styleTokenType == StyleTokenType.LessThan)
                {
                    tagName += tokenStream.Current.value;
                    tokenStream.Advance();
                    tagName += tokenStream.Current.value;
                    AssertTokenTypeAndAdvance(StyleTokenType.Identifier);
                    tagName += tokenStream.Current.value;
                    AssertTokenTypeAndAdvance(StyleTokenType.GreaterThan);
                }

                AssertTokenTypeAndAdvance(StyleTokenType.GreaterThan);
                break;

            // styleId { ... }
            case StyleTokenType.Identifier:
                identifier = tokenStream.Current.value;
                tokenStream.Advance();
                break;

            default:
                throw new ParseException(initialStyleToken, $"Expected style definition or tag name but found {initialStyleToken.styleTokenType}");
            }

            StyleRootNode styleRootNode = StyleASTNodeFactory.StyleRootNode(identifier, tagName);

            styleRootNode.WithLocation(initialStyleToken);
            nodes.Add(styleRootNode);

            // we just read an element name or style name
            // now move forward and expect an open curly brace

            // next there should be one of those:
            // - property
            // - state
            // - attribute with or without boolean modifier
            // - expression with constants
            ParseStyleGroupBody(styleRootNode);
        }
Exemplo n.º 21
0
        private StyleFunctionNode ParsePropertyFunction(string identifier)
        {
            StyleFunctionNode functionNode = StyleASTNodeFactory.StyleFunctionNode(identifier);

            while (tokenStream.HasMoreTokens && !AdvanceIfTokenType(StyleTokenType.ParenClose))
            {
                functionNode.AddChildNode(ParsePropertyValue());
                // we just ignore the comma for now
                AdvanceIfTokenType(StyleTokenType.Comma);
            }

            return(functionNode);
        }
Exemplo n.º 22
0
        private void ParseSoundProperty(SoundRootNode soundRootNode)
        {
            string propertyName = AssertTokenTypeAndAdvance(StyleTokenType.Identifier);

            AssertTokenTypeAndAdvance(StyleTokenType.EqualSign);
            StyleToken variableToken = tokenStream.Current;

            SoundPropertyNode propertyNode = StyleASTNodeFactory.SoundPropertyNode(propertyName, ParsePropertyValue());

            propertyNode.WithLocation(variableToken);

            soundRootNode.AddChildNode(propertyNode);
            AssertTokenTypeAndAdvance(StyleTokenType.EndStatement);
        }
Exemplo n.º 23
0
        private void ParseImportNode()
        {
            StyleToken importToken = tokenStream.Current;

            AssertTokenTypeAndAdvance(StyleTokenType.Import);
            string source = AssertTokenTypeAndAdvance(StyleTokenType.String);

            AssertTokenTypeAndAdvance(StyleTokenType.As);

            string alias = AssertTokenTypeAndAdvance(StyleTokenType.Identifier);

            AssertTokenTypeAndAdvance(StyleTokenType.EndStatement);

            nodes.Add(StyleASTNodeFactory.ImportNode(alias, source).WithLocation(importToken));
        }
Exemplo n.º 24
0
        private ConstNode ParseConstNode()
        {
            StyleToken constToken = tokenStream.Current;

            AssertTokenTypeAndAdvance(StyleTokenType.Const);
            // const name
            string variableName = AssertTokenTypeAndAdvance(StyleTokenType.Identifier);

            AssertTokenTypeAndAdvance(StyleTokenType.EqualSign);

            ConstNode constNode = StyleASTNodeFactory.ConstNode(variableName, ParsePropertyValue());

            constNode.WithLocation(constToken);
            return(constNode);
        }
Exemplo n.º 25
0
    public void ParsePropertyWithReference()
    {
        var nodes = StyleParser.Parse(@"
            style hasReferenceToBackgroundImagePath {
                Background = url(@pathRef);
            }
        ");

        Assert.AreEqual(1, nodes.Count);
        var property = (((PropertyNode)((StyleRootNode)nodes[0]).children[0]));

        Assert.AreEqual("Background", property.identifier);
        Assert.AreEqual(StyleASTNodeType.Url, property.children[0].type);

        var urlNode = (UrlNode)property.children[0];

        Assert.AreEqual(StyleASTNodeType.Url, urlNode.type);
        Assert.AreEqual(StyleASTNodeFactory.ConstReferenceNode("pathRef"), urlNode.url);
    }
Exemplo n.º 26
0
        private UnitNode ParseUnit()
        {
            StyleToken styleToken = tokenStream.Current;
            string     value      = styleToken.value;

            tokenStream.Advance();

            switch (styleToken.styleTokenType)
            {
            case StyleTokenType.Identifier:
                return(StyleASTNodeFactory.UnitNode(value));

            case StyleTokenType.Mod:
                return(StyleASTNodeFactory.UnitNode(value));

            default:
                throw new ParseException(styleToken, "Expected a token that looks like a unit but this didn't.");
            }
        }
Exemplo n.º 27
0
        private StyleASTNode ParseRgb()
        {
            AssertTokenTypeAndAdvance(StyleTokenType.Rgb);
            AssertTokenTypeAndAdvance(StyleTokenType.ParenOpen);

            StyleASTNode red = ParseLiteralOrReference(StyleTokenType.Number);

            AssertTokenTypeAndAdvance(StyleTokenType.Comma);

            StyleASTNode green = ParseLiteralOrReference(StyleTokenType.Number);

            AssertTokenTypeAndAdvance(StyleTokenType.Comma);

            StyleASTNode blue = ParseLiteralOrReference(StyleTokenType.Number);

            AssertTokenTypeAndAdvance(StyleTokenType.ParenClose);

            return(StyleASTNodeFactory.RgbNode(red, green, blue));
        }
Exemplo n.º 28
0
    public void CreateContextWithMultipleConstants()
    {
        LightList <StyleASTNode> nodes = new LightList <StyleASTNode>();

        nodes.Add(StyleASTNodeFactory.ExportNode(StyleASTNodeFactory.ConstNode("col0", StyleASTNodeFactory.ColorNode("red"))));
        nodes.Add(StyleASTNodeFactory.ExportNode(StyleASTNodeFactory.ConstNode("thing0", StyleASTNodeFactory.StringLiteralNode("someVal"))));
        nodes.Add(StyleASTNodeFactory.ExportNode(StyleASTNodeFactory.ConstNode("number", StyleASTNodeFactory.NumericLiteralNode("1"))));

        var context = new StyleSheetConstantImporter(new StyleSheetImporter(null, null)).CreateContext(nodes, default);

        Assert.AreEqual(3, context.constants.Count);
        Assert.AreEqual("col0", context.constants[0].name);
        Assert.True(context.constants[0].exported);

        Assert.AreEqual("thing0", context.constants[1].name);
        Assert.True(context.constants[1].exported);

        Assert.AreEqual("number", context.constants[2].name);
        Assert.True(context.constants[2].exported);
    }
Exemplo n.º 29
0
    public void ParseAttributeGroup()
    {
        var nodes = StyleParser.Parse(@"
            style hasBackgroundOnHover {
                [attr:attrName] { Background = url(@pathRef); }
            }
        ");

        Assert.AreEqual(1, nodes.Count);
        var attributeGroupContainer = (((AttributeNodeContainer)((StyleRootNode)nodes[0]).children[0]));

        Assert.AreEqual("attrName", attributeGroupContainer.identifier);

        var property = (PropertyNode)attributeGroupContainer.children[0];

        Assert.AreEqual("Background", property.identifier);
        Assert.AreEqual(StyleASTNodeType.Url, property.children[0].type);

        var urlNode = (UrlNode)property.children[0];

        Assert.AreEqual(StyleASTNodeFactory.ConstReferenceNode("pathRef"), urlNode.url);
    }
Exemplo n.º 30
0
        private StyleASTNode ParsePropertyValue()
        {
            StyleToken   propertyToken = tokenStream.Current;
            StyleASTNode propertyValue;

            switch (tokenStream.Current.styleTokenType)
            {
            case StyleTokenType.Number:
                StyleLiteralNode value = StyleASTNodeFactory.NumericLiteralNode(tokenStream.Current.value).WithLocation(propertyToken) as StyleLiteralNode;
                tokenStream.Advance();
                if (!IsAnyTokenType(StyleTokenType.EndStatement, StyleTokenType.Number, StyleTokenType.Comma, StyleTokenType.ParenClose))
                {
                    UnitNode unit = ParseUnit().WithLocation(tokenStream.Previous) as UnitNode;
                    propertyValue = StyleASTNodeFactory.MeasurementNode(value, unit);
                }
                else
                {
                    propertyValue = value;
                }

                break;

            case StyleTokenType.String:

                propertyValue = StyleASTNodeFactory.StringLiteralNode(tokenStream.Current.value);
                tokenStream.Advance();

                if (tokenStream.Current == StyleTokenType.BracesOpen)
                {
                    TextUtil.StringBuilder.Clear();
                    StyleLiteralNode n = (StyleLiteralNode)propertyValue;

                    TextUtil.StringBuilder.Append("\"");
                    TextUtil.StringBuilder.Append(n.rawValue);
                    TextUtil.StringBuilder.Append("\" ");

                    while (tokenStream.HasMoreTokens && tokenStream.Current != StyleTokenType.BracesClose)
                    {
                        TextUtil.StringBuilder.Append(tokenStream.Current.value);
                        tokenStream.Advance();
                    }

                    TextUtil.StringBuilder.Append(tokenStream.Current.value);

                    tokenStream.Advance();
                    n.rawValue = TextUtil.StringBuilder.ToString();
                    TextUtil.StringBuilder.Clear();
                }

                break;

            case StyleTokenType.Identifier:
                string identifier = tokenStream.Current.value;
                tokenStream.Advance();
                if (tokenStream.Current.styleTokenType == StyleTokenType.ParenOpen)
                {
                    tokenStream.Advance();
                    propertyValue = ParsePropertyFunction(identifier);
                }
                else
                {
                    propertyValue = StyleASTNodeFactory.IdentifierNode(identifier);
                }

                break;

            case StyleTokenType.Rgba:
                propertyValue = ParseRgba();
                break;

            case StyleTokenType.Rgb:
                propertyValue = ParseRgb();
                break;

            case StyleTokenType.HashColor:
                propertyValue = StyleASTNodeFactory.ColorNode(tokenStream.Current.value);
                tokenStream.Advance();
                break;

            case StyleTokenType.Url:
                tokenStream.Advance();
                AssertTokenTypeAndAdvance(StyleTokenType.ParenOpen);

                StyleASTNode url;
                StyleASTNode spriteName = null;
                if (tokenStream.Current.styleTokenType == StyleTokenType.String)
                {
                    url = ParseLiteralOrReference(StyleTokenType.String);
                }
                else
                {
                    url = ParseLiteralOrReference(StyleTokenType.Identifier);
                }

                if (url is StyleIdentifierNode urlIdentifier)
                {
                    // todo -- this doesn't handle spaces!
                    while (tokenStream.HasMoreTokens && !AdvanceIfTokenType(StyleTokenType.ParenClose))
                    {
                        // advancing tokens no matter the type. We want to concatenate all identifiers and slashes of a path again.
                        urlIdentifier.name += tokenStream.Current.value;
                        spriteName          = ParseSpriteName();
                        tokenStream.Advance();
                    }
                }
                else if (url is StyleLiteralNode || url is ConstReferenceNode)
                {
                    spriteName = ParseSpriteName();
                    AssertTokenTypeAndAdvance(StyleTokenType.ParenClose);
                }
                else
                {
                    throw new CompileException(url, "URL could not be parsed.");
                }

                propertyValue = StyleASTNodeFactory.UrlNode(url, spriteName);
                break;

            case StyleTokenType.At:
                propertyValue = ParseConstReference();
                break;

            case StyleTokenType.Dollar:
                propertyValue = ParseVariableReference();
                break;

            default:
                throw new ParseException(propertyToken, "Expected a property value but found no valid token.");
            }

            return(propertyValue.WithLocation(propertyToken));
        }