]> O.S.I.I.S - jp/crow.git/commitdiff
change styling grammar for value now enclose in double quote
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Tue, 27 Feb 2018 23:51:17 +0000 (00:51 +0100)
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>
Tue, 27 Feb 2018 23:51:17 +0000 (00:51 +0100)
Crow.csproj
Default.style
src/ParsingException.cs [new file with mode: 0644]
src/StyleReader.cs

index 41e556f8d177c724afa5db21c4802191e972f40b..91b16e313ca1513089c58a586ccdc151b8650555 100644 (file)
     <Compile Include="src\DragDropEventArgs.cs" />
     <Compile Include="src\GraphicObjects\Docker.cs" />
     <Compile Include="src\GraphicObjects\DockWindow.cs" />
+    <Compile Include="src\ParsingException.cs" />
   </ItemGroup>
   <ItemGroup>
     <Reference Include="System" />
index 11a221917fd7b7c978928b515049e907d69e5bf2..2e9e72a1af06333fbc6ea7f118e12e4f9dfc1ec8 100644 (file)
 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 (file)
index 0000000..e3bd51c
--- /dev/null
@@ -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)
+               {}
+       }
+}
+
index 5a00a594e915a3bdfc79817601ccc87586f1ff74..28eaf7808b0c845657a828559abc73df573424e6 100644 (file)
@@ -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<string, Style> styling, Stream stream, string resId)
                        : base(stream)
                {
@@ -52,116 +91,95 @@ namespace Crow
                        List<string> targetsClasses = new List<string> ();
                        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<string> ();
-                                               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 ()