From 19944e8637bdec5a873c8a5c690973d9ff134c6d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Wed, 28 Feb 2018 00:51:17 +0100 Subject: [PATCH] change styling grammar for value now enclose in double quote --- Crow.csproj | 1 + Default.style | 220 ++++++++++++++++++++-------------------- src/ParsingException.cs | 20 ++++ src/StyleReader.cs | 220 ++++++++++++++++++++++------------------ 4 files changed, 250 insertions(+), 211 deletions(-) create mode 100644 src/ParsingException.cs diff --git a/Crow.csproj b/Crow.csproj index 41e556f8..91b16e31 100644 --- a/Crow.csproj +++ b/Crow.csproj @@ -222,6 +222,7 @@ + diff --git a/Default.style b/Default.style index 11a22191..2e9e72a1 100644 --- a/Default.style +++ b/Default.style @@ -1,184 +1,184 @@ Button, CheckBox, RadioButton, ComboBox, Expandable, MessageBox, Popper, Slider, Spinner, TextBox { - Focusable = true; - Height = Fit; + Focusable = "true"; + Height = "Fit"; } Border { - Foreground = Gray; + Foreground = "Gray"; } -CheckBox { Caption = CheckBox; } -RadioButton { Caption = RadioButton; } -Expandable { Caption = Expandable; } -Popper { Caption = Popper;} -GroupBox { Caption = Group Box; } +CheckBox { Caption = "CheckBox"; } +RadioButton { Caption = "RadioButton"; } +Expandable { Caption = "Expandable"; } +Popper { Caption = "Popper";} +GroupBox { Caption = "Group Box"; } ControlBorder { - BorderWidth = 1; - Foreground = Jet; - Background = Transparent; + BorderWidth = "1"; + Foreground = "Jet"; + Background = "Transparent"; } ControlCaption { - Foreground = Gray; - MouseEnter = {Foreground=White}; - MouseLeave = {Foreground=Gray}; + Foreground = "Gray"; + MouseEnter = "{Foreground=White}"; + MouseLeave = "{Foreground=Gray}"; } Icon { - Margin=1; - Width=12; - Height=12; + Margin = "1"; + Width = "12"; + Height = "12"; } Wrapper { - Orientation = Vertical; + Orientation = "Vertical"; } Button { - Caption = Button; - Width = Fit; + Caption = "Button"; + Width = "Fit"; } Label { - Height = Fit; - Width = Fit; - Margin = 0; + Height = "Fit"; + Width = "Fit"; + Margin = "0"; } Menu { - Margin = 1; - Background = vgradient|0:DimGray|1:Onyx; - Height = Fit; - Width = Stretched; - VerticalAlignment = Top; - SelectionBackground = Transparent; + Margin = "1"; + Background = "vgradient|0:DimGray|1:Onyx"; + Height = "Fit"; + Width = "Stretched"; + VerticalAlignment = "Top"; + SelectionBackground = "Transparent"; } MenuItem { - Caption = MenuItem; - Width = Stretched; - Height = Fit; - Background = Transparent; - Foreground = LightGray; - MouseEnter = {Background = vgradient|0:UnitedNationsBlue|1:Onyx;Foreground=White;} - MouseLeave = {Foreground=LightGray;Background=Transparent;} - SelectionBackground = Transparent; + Caption = "MenuItem"; + Width = "Stretched"; + Height = "Fit"; + Background = "Transparent"; + Foreground = "LightGray"; + MouseEnter = "{Background = vgradient|0:UnitedNationsBlue|1:Onyx;Foreground=White;}"; + MouseLeave = "{Foreground=LightGray;Background=Transparent;}"; + SelectionBackground = "Transparent"; } Docker { - AllowDrop = true; + AllowDrop = "true"; } DockWindow { - AllowDrag = true; + AllowDrag = "true"; } MessageBox { - Background = 0.3,0.3,0.3,0.3; - Width = Fit; - Title=MessageBox; - Font = serif, 12; - MinimumSize = 200,120; - AlwaysOnTop = true; + Background = "0.3,0.3,0.3,0.3"; + Width = "Fit"; + Caption="MessageBox"; + Font = "serif, 12"; + MinimumSize = "200,120"; + AlwaysOnTop = "true"; } Slider { - Background = vgradient|0:Black|0.1:Gray|0.9:Gray|1:LightGray; - Foreground = Gray; - Width = Fit; + Background = "vgradient|0:Black|0.1:Gray|0.9:Gray|1:LightGray"; + Foreground = "Gray"; + Width = "Fit"; } Splitter { - Focusable = true; - Background = DimGray; + Focusable = "true"; + Background = "DimGray"; } Spinner { - Foreground = DimGray; + Foreground = "DimGray"; } TabView { - CacheEnabled = false; + CacheEnabled = "false"; } TabItem { - Caption = TabItem; - Focusable = true; - CacheEnabled = false; + Caption = "TabItem"; + Focusable = "true"; + CacheEnabled = "false"; } TextBox { - Background = White; - Foreground = Black; - Selectable = True; - Text = TextBox; - Margin = 1; + Background = "White"; + Foreground = "Black"; + Selectable = "True"; + Text = "TextBox"; + Margin = "1"; } Window { - Caption = Window; - Focusable = true; - MinimumSize=5,5; - Width = 150; - Height = 150; + Caption = "Window"; + Focusable = "true"; + MinimumSize="5,5"; + Width = "150"; + Height = "150"; } ToolWindow { - Caption = Window; - Template = #Crow.ToolWindow.template; - Focusable = true; - MinimumSize=50,50; - Width = 150; - Height = 150; + Caption = "Window"; + Template = "#Crow.ToolWindow.template"; + Focusable = "true"; + MinimumSize="50,50"; + Width = "150"; + Height = "150"; } DocksView { - AllowDrop = true; + AllowDrop = "true"; } DockingView { - Focusable = true; - AllowDrag = true; + Focusable = "true"; + AllowDrag = "true"; } FileDialog { - Template = #Crow.FileDialog.template; - AlwaysOnTop = true; - Focusable = true; - MinimumSize=50,50; - Width = 500; - Height = 300; + Template = "#Crow.FileDialog.template"; + AlwaysOnTop = "true"; + Focusable = "true"; + MinimumSize="50,50"; + Width = "500"; + Height = "300"; } ProgressBar { - Foreground = vgradient|0:BlueCrayola|0.5:SkyBlue|1:BlueCrayola; + Foreground = "vgradient|0:BlueCrayola|0.5:SkyBlue|1:BlueCrayola"; } ScrollBar { - Maximum = 0; - Value = 0; + Maximum = "0"; + Value = "0"; } Scroller { - CacheEnabled = false; + CacheEnabled = "false"; } Control { - Margin=0; - Spacing=3; + Margin="0"; + Spacing="3"; } SaturationValueSelector { - Foreground=Red; + Foreground="Red"; } HueSelector { - ClipToClientRect=False; + ClipToClientRect="False"; } ColorSpinner { - Minimum = 0; - Maximum = 255; - SmallIncrement = 1; + Minimum = "0"; + Maximum = "255"; + SmallIncrement = "1"; } HSVSpinner { - Minimum = 0; - Maximum = 1; - SmallIncrement = 0.01; + Minimum = "0"; + Maximum = "1"; + SmallIncrement = "0.01"; } TxtInFileDialog { - Margine = 1; - Font = droid, 12; + Margine = "1"; + Font = "droid, 12"; } CheckBoxAlt { - Template= #Crow.Templates.CheckBox2.template; - Background = Transparent; - Checked={Background=DarkSlateGray;Foreground=LightGray;}; - Unchecked = {Background=Transparent;Foreground=DimGray;}; + Template= "#Crow.Templates.CheckBox2.template"; + Background = "Transparent"; + Checked="{Background=DarkSlateGray;Foreground=LightGray;}"; + Unchecked = "{Background=Transparent;Foreground=DimGray;}"; } ArrowBut { - MouseRepeat=true; - Height=Fit; - Width=Fit; - Focusable=true; - Foreground=Jet; - Background=hgradient|0:Gray|1:Jet; - MouseDown={Background=hgradient|0:White|0.4:BlueCrayola|1:Jet}; - MouseUp={Background=hgradient|0:Gray|1:Jet}; - MouseEnter={Foreground=Black}; - MouseLeave={Foreground=Jet}; + MouseRepeat="true"; + Height="Fit"; + Width="Fit"; + Focusable="true"; + Foreground="Jet"; + Background="hgradient|0:Gray|1:Jet"; + MouseDown="{Background=hgradient|0:White|0.4:BlueCrayola|1:Jet}"; + MouseUp="{Background=hgradient|0:Gray|1:Jet}"; + MouseEnter="{Foreground=Black}"; + MouseLeave="{Foreground=Jet}"; } \ No newline at end of file diff --git a/src/ParsingException.cs b/src/ParsingException.cs new file mode 100644 index 00000000..e3bd51c9 --- /dev/null +++ b/src/ParsingException.cs @@ -0,0 +1,20 @@ +using System; + +namespace Crow.Coding +{ + public class ParserException : Exception + { + public int Line; + public int Column; + public ParserException(int line, int column, string txt) + : base(string.Format("Parser exception ({0},{1}): {2}", line, column, txt)) + { + Line = line; + Column = column; + } + public ParserException(int line, int column, string txt, Exception innerException) + : base(string.Format("Parser exception ({0},{1}): {2}", line, column, txt), innerException) + {} + } +} + diff --git a/src/StyleReader.cs b/src/StyleReader.cs index 5a00a594..28eaf780 100644 --- a/src/StyleReader.cs +++ b/src/StyleReader.cs @@ -28,6 +28,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Reflection; +using System.Text.RegularExpressions; +using Crow.Coding; namespace Crow { @@ -37,12 +39,49 @@ namespace Crow //TODO: style key shared by different class may use only first encouneter class setter, which can cause bug. public class StyleReader : StreamReader { - enum readerState { classNames, propertyName, expression } - readerState state = readerState.classNames; + enum States { init, classNames, members, value, endOfStatement } + + States curState = States.init; + string resourceId; int column = 1; int line = 1; + #region Character ValidityCheck + static Regex rxValidChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxNameStartChar = new Regex(@"_|\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}"); + static Regex rxNameChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + static Regex rxDecimal = new Regex(@"[0-9]+"); + static Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); + + public bool nextCharIsValidCharStartName + { + get { return rxNameStartChar.IsMatch(new string(new char[]{PeekChar()})); } + } + public bool nextCharIsValidCharName + { + get { return rxNameChar.IsMatch(new string(new char[]{PeekChar()})); } + } + #endregion + + char ReadChar () { + column++; + return (Char)Read(); + } + char PeekChar () { + return (Char)Peek(); + } + void SkipWhiteSpaceAndLineBreak (){ + while (!EndOfStream){ + if (!PeekChar ().IsWhiteSpaceOrNewLine ()) + break; + if (ReadChar () == '\n') { + line++; + column = 0; + } + } + } + public StyleReader (Dictionary styling, Stream stream, string resId) : base(stream) { @@ -52,116 +91,95 @@ namespace Crow List targetsClasses = new List (); string currentProperty = ""; - int curlyBracketCount = 0; - while (!EndOfStream) { - char c = (Char)Read (); - if (c == '/' && !EndOfStream) { - if ((char)Peek () == '/') {//process comment, skip until newline - ReadLine (); - continue; - } - } - switch (state) { - case readerState.classNames: - if (c.IsWhiteSpaceOrNewLine () || c == ',' || c == '{') { - if (!string.IsNullOrEmpty (token)) - targetsClasses.Add (token); - if (c == '{') - state = readerState.propertyName; - token = ""; - }else if (c=='='){ - //this file contains only properties, - //resource Id (minus .style extention) will determine the single target class - if (targetsClasses.Count > 1) - throwParserException ("Unexpected token '='"); - else if (targetsClasses.Count == 1) { - if (!string.IsNullOrEmpty (token)) - throwParserException ("Unexpected token '='"); - currentProperty = targetsClasses [0]; - targetsClasses [0] = styleKey; - }else{ - if (string.IsNullOrEmpty (token)) - throwParserException ("Unexpected token '='"); - targetsClasses.Add (styleKey); - currentProperty = token; - token = ""; - } - state = readerState.expression; - }else - token += c; + SkipWhiteSpaceAndLineBreak (); + if (EndOfStream) break; - case readerState.propertyName: - if (c.IsWhiteSpaceOrNewLine () || c == '=') { - if (!string.IsNullOrEmpty (token)) - currentProperty = token; - if (c == '=') - state = readerState.expression; - token = ""; - }else if (c == '}'){ - if (!string.IsNullOrEmpty (token)) - throwParserException ("Unexpected token '" + c + "'"); - targetsClasses = new List (); - currentProperty = ""; - state = readerState.classNames; - } else - token += c; + switch (Peek()) { + case '/': + ReadChar (); + if (PeekChar () != '/') + throw new ParserException (line, column, "Unexpected char '/'"); + ReadLine (); + break; + case ',': + ReadChar (); + if (!(curState == States.init || curState == States.classNames) || string.IsNullOrEmpty (token)) + throw new ParserException (line, column, "Unexpected char ','"); + targetsClasses.Add (token); + token = ""; + curState = States.classNames; + break; + case '{': + ReadChar (); + if (!(curState == States.init || curState == States.classNames) || string.IsNullOrEmpty (token)) + throw new ParserException (line, column, "Unexpected char '{'"); + targetsClasses.Add (token); + token = ""; + curState = States.members; + break; + case '}': + ReadChar (); + if (curState != States.members) + throw new ParserException (line, column, "Unexpected char '}'"); + curState = States.classNames; + targetsClasses.Clear (); + break; + case '=': + ReadChar (); + if (!(curState == States.init || curState == States.members)) + throw new ParserException (line, column, "Unexpected char '='"); + currentProperty = token; + token = ""; + curState = States.value; break; - case readerState.expression: - bool expressionIsFinished = false; - if (curlyBracketCount == 0) { - if (c == '{'){ - if (!string.IsNullOrEmpty(token.Trim())) - throwParserException ("Unexpected token '{'"); - curlyBracketCount++; - token = "{"; - }else if (c == '}') - throwParserException ("Unexpected token '{'"); - else if (c == ';') { - expressionIsFinished = true; - } else - token += c; - } else { - if (c == '{') - curlyBracketCount++; - else if (c == '}') { - curlyBracketCount--; - if (curlyBracketCount == 0) - expressionIsFinished = true; + case '"': + if (curState != States.value) + throw new ParserException (line, column, "Unexpected char '\"'"); + ReadChar (); + + while (!EndOfStream) { + char c = PeekChar(); + if (c == '\"') { + ReadChar (); + break; } - token += c; + token += ReadChar(); + if (c == '\\' && !EndOfStream) + token += ReadChar(); + } + curState = States.endOfStatement; + break; + case ';': + if (curState != States.endOfStatement) + throw new ParserException (line, column, "Unexpected end of statement"); + ReadChar (); + foreach (string tc in targetsClasses) { + if (!styling.ContainsKey (tc)) + styling [tc] = new Style (); + else if (styling [tc].ContainsKey (currentProperty)) + continue; + styling [tc] [currentProperty] = token; + System.Diagnostics.Debug.WriteLine ("Style: {0}.{1} = {2}", tc, currentProperty, token); } - if (expressionIsFinished) { - if (!string.IsNullOrEmpty (token)) { - string expression = token.Trim (); + token = ""; + curState = States.members; + break; + default: + if (curState == States.value) + throw new ParserException (line, column, "expecting value enclosed in '\"'"); + if (curState == States.endOfStatement) + throw new ParserException (line, column, "expecting end of statement"); - foreach (string tc in targetsClasses) { - if (!styling.ContainsKey (tc)) - styling [tc] = new Style (); - else if (styling [tc].ContainsKey (currentProperty)) - continue; - styling [tc] [currentProperty] = expression; - } - token = ""; - } - //allow omiting ';' if curly bracket close expression - while (!EndOfStream) { - if (Char.IsWhiteSpace((char)Peek())) - Read(); - else - break; - } - if (this.Peek () == ';') - this.Read (); - state = readerState.propertyName; + if (nextCharIsValidCharStartName) { + token += ReadChar(); + while (nextCharIsValidCharName) + token += ReadChar(); } break; } } - - if (curlyBracketCount > 0) - throwParserException ("Unexpected end of file"); } public override int Read () -- 2.47.3