/// <summary> /// Consumes the stream only if the current token belongs to a command definition. /// </summary> /// <param name="styleRootNode"></param> /// <returns>true in case the current token belongs to a command definition. False if it does not.</returns> private bool TryParseCommand(StyleNodeContainer styleRootNode) { switch (tokenStream.Current.styleTokenType) { case StyleTokenType.Exit: tokenStream.Advance(); AssertTokenTypeAndAdvance(StyleTokenType.BracketClose); styleRootNode.AddChildNode(ParseRunNode(RunCommandType.Exit, ParseCommandAttribute())); return(true); case StyleTokenType.Enter: tokenStream.Advance(); AssertTokenTypeAndAdvance(StyleTokenType.BracketClose); styleRootNode.AddChildNode(ParseRunNode(RunCommandType.Enter, ParseCommandAttribute())); return(true); case StyleTokenType.EnterExit: tokenStream.Advance(); AssertTokenTypeAndAdvance(StyleTokenType.BracketClose); styleRootNode.AddChildNode(ParseRunNode(RunCommandType.EnterExit, ParseCommandAttribute())); return(true); default: return(false); } }
private void ParseProperties(StyleNodeContainer styleRootNode) { while (tokenStream.HasMoreTokens && tokenStream.Current.styleTokenType != StyleTokenType.BracesClose) { ParseProperty(styleRootNode); } }
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:...)"); } }
private void ParseProperty(StyleNodeContainer styleRootNode, bool parsingKeyframes = false) { StyleToken propertyNodeToken = tokenStream.Current; string propertyName; if (AdvanceIfTokenType(StyleTokenType.Cursor)) { propertyName = propertyNodeToken.value; } else if (AdvanceIfTokenType(StyleTokenType.Run)) { styleRootNode.AddChildNode(ParseRunNode(RunCommandType.Enter, RunAction.Run)); return; } else if (AdvanceIfTokenType(StyleTokenType.Pause)) { styleRootNode.AddChildNode(ParseRunNode(RunCommandType.Enter, RunAction.Pause)); return; } else if (AdvanceIfTokenType(StyleTokenType.Stop)) { styleRootNode.AddChildNode(ParseRunNode(RunCommandType.Enter, RunAction.Stop)); return; } else if (AdvanceIfTokenType(StyleTokenType.BracketOpen)) { if (TryParseCommand(styleRootNode)) { return; } throw new ParseException(tokenStream.Current, "Not sure what you tried here but at this point only [enter] and [exit] run animation would be legal."); } else { propertyName = AssertTokenTypeAndAdvance(StyleTokenType.Identifier); if (propertyName == "material" || propertyName == "Material") { if (tokenStream.Current == StyleTokenType.Colon) { tokenStream.Advance(); string materialName = AssertTokenTypeAndAdvance(StyleTokenType.Identifier); AssertTokenTypeAndAdvance(StyleTokenType.Dot); string materialPropertyName = AssertTokenTypeAndAdvance(StyleTokenType.Identifier); AssertTokenTypeAndAdvance(StyleTokenType.EqualSign); TextUtil.StringBuilder.Clear(); while (tokenStream.HasMoreTokens && tokenStream.Current != StyleTokenType.EndStatement) { TextUtil.StringBuilder.Append(tokenStream.Current.value); tokenStream.Advance(); } tokenStream.Advance(); MaterialPropertyNode materialPropertyNode = new MaterialPropertyNode { materialName = materialName, identifier = materialPropertyName, value = TextUtil.StringBuilder.ToString() }; TextUtil.StringBuilder.Clear(); materialPropertyNode.WithLocation(propertyNodeToken); styleRootNode.AddChildNode(materialPropertyNode); return; } } } AssertTokenTypeAndAdvance(StyleTokenType.EqualSign); PropertyNode propertyNode = StyleASTNodeFactory.PropertyNode(propertyName); propertyNode.WithLocation(propertyNodeToken); while (tokenStream.HasMoreTokens && !AdvanceIfTokenType(StyleTokenType.EndStatement)) { propertyNode.AddChildNode(ParsePropertyValue()); // we just ignore the comma for now AdvanceIfTokenType(StyleTokenType.Comma); } styleRootNode.AddChildNode(propertyNode); }
private void ParseStyleGroupBody(StyleNodeContainer styleRootNode) { AssertTokenTypeAndAdvance(StyleTokenType.BracesOpen); while (tokenStream.HasMoreTokens && !AdvanceIfTokenType(StyleTokenType.BracesClose)) { switch (tokenStream.Current.styleTokenType) { case StyleTokenType.Not: { groupOperatorStack.Push(StyleOperatorType.Not); tokenStream.Advance(); ParseAttributeOrExpressionGroup(); break; } case StyleTokenType.And: tokenStream.Advance(); if (AdvanceIfTokenType(StyleTokenType.Not)) { groupOperatorStack.Push(StyleOperatorType.Not); } ParseAttributeOrExpressionGroup(); break; case StyleTokenType.BracketOpen: tokenStream.Advance(); if (!TryParseCommand(styleRootNode)) { ParseStateOrAttributeGroup(styleRootNode); } break; case StyleTokenType.Cursor: // special case here: we are out of words and need to use the // cursor token for the property AND the top level definition ¯\_(ツ)_/¯ ParseProperty(styleRootNode); break; case StyleTokenType.Identifier: ParseProperty(styleRootNode); break; case StyleTokenType.Run: tokenStream.Advance(); styleRootNode.AddChildNode(ParseRunNode(RunCommandType.Enter, RunAction.Run)); break; case StyleTokenType.Stop: tokenStream.Advance(); styleRootNode.AddChildNode(ParseRunNode(RunCommandType.Enter, RunAction.Stop)); break; case StyleTokenType.Pause: tokenStream.Advance(); styleRootNode.AddChildNode(ParseRunNode(RunCommandType.Enter, RunAction.Pause)); break; case StyleTokenType.BracesOpen: { // At this point only unconsumed attribute/expression group bodies are allowed if (groupExpressionStack.Count > 1) { throw new ParseException(tokenStream.Current, "There was a problem, I somehow made an error parsing a combined style group..."); } if (groupExpressionStack.Count == 1) { AttributeNodeContainer attributeNodeContainer = groupExpressionStack.Pop(); ParseStyleGroupBody(attributeNodeContainer); styleRootNode.AddChildNode(attributeNodeContainer); } else { throw new ParseException(tokenStream.Current, "Expected an attribute style group body. Braces are in a weird position!"); } break; } default: throw new ParseException(tokenStream.Current, "Expected either a boolean group operator (not / and), the start" + " of a group (an open bracket) or a regular property identifier but found " + tokenStream.Current.styleTokenType + " with value " + tokenStream.Current.value); } } }
private void CompileStyleGroups(StyleNodeContainer root, StyleType styleType, LightList <UIStyleGroup> groups, UIStyleGroup targetGroup, AnimationData[] styleSheetAnimations, UISoundData[] uiSoundData) { for (int index = 0; index < root.children.Count; index++) { StyleASTNode node = root.children[index]; switch (node) { case SelectNode selectNode: break; case PropertyNode propertyNode: // add to normal ui style set StylePropertyMappers.MapProperty(targetGroup.normal.style, propertyNode, context); break; case AttributeNodeContainer attribute: if (root is AttributeNodeContainer) { throw new CompileException(attribute, "You cannot nest attribute group definitions."); } UIStyleGroup attributeGroup = new UIStyleGroup(); attributeGroup.normal = UIStyleRunCommand.CreateInstance(); attributeGroup.name = root.identifier; attributeGroup.rule = MapAttributeContainerToRule(attribute); attributeGroup.styleType = styleType; groups.Add(attributeGroup); CompileStyleGroups(attribute, styleType, groups, attributeGroup, styleSheetAnimations, uiSoundData); break; case RunNode runNode: UIStyleRunCommand cmd = new UIStyleRunCommand() { style = targetGroup.normal.style, runCommands = targetGroup.normal.runCommands ?? new LightList <IRunCommand>(4) }; if (runNode.command is AnimationCommandNode animationCommandNode) { MapAnimationCommand(styleSheetAnimations, cmd, animationCommandNode); } else if (runNode.command is SoundCommandNode soundCommandNode) { MapSoundCommand(uiSoundData, cmd, soundCommandNode); } targetGroup.normal = cmd; break; case StyleStateContainer styleContainer: if (styleContainer.identifier == "hover") { UIStyleRunCommand uiStyleRunCommand = targetGroup.hover; uiStyleRunCommand.style = uiStyleRunCommand.style ?? new UIStyle(); MapProperties(styleSheetAnimations, uiSoundData, ref uiStyleRunCommand, styleContainer.children); targetGroup.hover = uiStyleRunCommand; } else if (styleContainer.identifier == "focus") { UIStyleRunCommand uiStyleRunCommand = targetGroup.focused; uiStyleRunCommand.style = uiStyleRunCommand.style ?? new UIStyle(); MapProperties(styleSheetAnimations, uiSoundData, ref uiStyleRunCommand, styleContainer.children); targetGroup.focused = uiStyleRunCommand; } else if (styleContainer.identifier == "active") { UIStyleRunCommand uiStyleRunCommand = targetGroup.active; uiStyleRunCommand.style = uiStyleRunCommand.style ?? new UIStyle(); MapProperties(styleSheetAnimations, uiSoundData, ref uiStyleRunCommand, styleContainer.children); targetGroup.active = uiStyleRunCommand; } else { throw new CompileException(styleContainer, $"Unknown style state '{styleContainer.identifier}'. Please use [hover], [focus] or [active] instead."); } break; default: throw new CompileException(node, $"You cannot have a {node} at this level."); } } }