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}!"); }
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); } }
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); }
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); }
internal static StyleStateContainer StateGroupRootNode(StyleToken token) { StyleStateContainer rootNode = s_StyleContainerNodePool.Get(); rootNode.type = StyleASTNodeType.StateGroup; rootNode.identifier = token.value; rootNode.WithLocation(token); return(rootNode); }
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); }
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); }
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); }
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); }
/// <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); }
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); }
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)); }
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); }
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."); } }
private void ParseAnimationVariables(AnimationRootNode rootNode) { while (tokenStream.HasMoreTokens && !AdvanceIfTokenType(StyleTokenType.BracesClose)) { StyleToken typeToken = tokenStream.Current; string typeIdentifier = AssertTokenTypeAndAdvance(StyleTokenType.Identifier); bool typeFound = false; for (int index = 0; index < s_SupportedVariableTypes.Length; index++) { (string name, Type type) = s_SupportedVariableTypes[index]; if (name == typeIdentifier) { string variableName = AssertTokenTypeAndAdvance(StyleTokenType.Identifier); AssertTokenTypeAndAdvance(StyleTokenType.EqualSign); StyleToken variableToken = tokenStream.Current; VariableDefinitionNode varNode = new VariableDefinitionNode(); varNode.name = variableName; varNode.variableType = type; varNode.value = ParsePropertyValue(); varNode.WithLocation(variableToken); rootNode.AddVariableNode(varNode); typeFound = true; break; } } if (!typeFound) { throw new ParseException(typeToken, "Unsupported Type; please read the manual!"); } AssertTokenTypeAndAdvance(StyleTokenType.EndStatement); } }
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)); }
public ParseException(StyleToken token, string message = null) : base($"Parse error at line {token.line}, column {token.column}, token type '{token.styleTokenType}' -> {token.value}\n{message}") { this.token = token; }
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); }
public StyleASTNode WithLocation(StyleToken token) { this.line = token.line; this.column = token.column; return(this); }