css1.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package style
  2. import "github.com/yhirose/go-peg"
  3. import "fmt"
  4. import "os"
  5. import "io/ioutil"
  6. import "errors"
  7. const CSS1PEG =
  8. `
  9. # CSS1 parser for a PEG parser generator.
  10. # and a user command parser
  11. # Doesn't support import statements.
  12. STYLESHEET ← (CDO / CDC)* (RULESET/DECLARATIONS/COMMENT/ATRULE)* (CDO / CDC)*
  13. RULESET ← SELECTORS "{" DECLARATIONS? "}"
  14. SELECTORS ← SELECTOR ("," SELECTOR)*
  15. SELECTOR ← ( "*" / NAME ID? CLASS? PSEUDO_CLASS? /
  16. ID CLASS? PSEUDO_CLASS? /
  17. CLASS PSEUDO_CLASS? /
  18. PSEUDO_CLASS )+ PSEUDO_ELEMENT* / PSEUDO_ELEMENT
  19. ATRULE ← ATID (STRING / URL) ";" / ATID "{" DECLARATIONS "}"
  20. NAME ← <IDENT>
  21. DECLARATIONS ← DECLARATION (';' DECLARATION)* ';'?
  22. DECLARATION ← NAME ":" EXPR PRIO? / COMMENT
  23. OPERATOR ← '/' / ','
  24. # UNARY_OPERATOR ← '-' / '+'
  25. PRIO ← IMPORTANT
  26. EXPR ← TERM (OPERATOR TERM)*
  27. TERM ← STRING / PERCENTAGE / LENGTH / HEXCOLOR / URL / RGB / NUM / IDENT
  28. ~COMMENT ← "/*" (!("*/").)* "*/"
  29. ATID ← < "@" [a-zA-Z][-_a-zA-Z0-9]+ >
  30. IMPORTANT ← < "!" WS "important" >
  31. IDENT ← < [-_a-zA-Z][-_a-zA-Z0-9]* >
  32. PERCENTAGE ← < NUM > "%"
  33. NUM ← < [+-]*[0-9]+ / [0-9]* "." [0-9]+ >
  34. LENGTH ← NUM UNIT
  35. UNIT ← <"pt" / "mm" / "pt" / "in" / "px" / "em" / "ex" >
  36. PSEUDO_ELEMENT ← <":first-letter" / ":first-line" >
  37. PSEUDO_CLASS ← <":hover" / ":link" / ":mark" / ":active" / ":visited" >
  38. HEXCOLOR ← "#" < ([0-9a-fA-F])+ >
  39. ID ← "#" < IDENT >
  40. CLASS ← "." < IDENT >
  41. # Raw string macro.
  42. RAWSM(O,C) ← O < (!(C).)* > C
  43. # Escaped string macro.
  44. ESCSM(O,C) ← O < (!(C)STRCHAR)* > C
  45. # String escapes
  46. STRESC1 ← "\\" [nrtfv\'\\"\[\]\\]
  47. STRESC2 ← "\\" [0-3] [0-7] [0-7]
  48. STRESC3 ← "\\" [0-7] [0-7]*
  49. STRESC4 ← "\\x" [0-9a-fA-F] [0-9a-fA-F]?
  50. STRESC5 ← "\\u" [0-9a-fA-F]+
  51. STRNOESC ← (!('\\\\').)
  52. STRCHAR ← STRESC1 / STRESC2 / STRESC3 / STRESC4 / STRESC5 / STRNOESC
  53. # Strings
  54. STRING ← ESCSM("\"", "\"") / ESCSM("'", "'")
  55. URL ← "url(" STRING ")"
  56. RGB ← < "rgb("[ \t]*[0-9]+[ \t]* "," [ \t]*[0-9]+[ \t]* "," [ \t]*[0-9]+[ \t]* ")" >
  57. ~WS ← [ \t\n\r]*
  58. CDO ← "<!--"
  59. CDC ← "-->"
  60. %whitespace ← [ \t\n\r]*
  61. `
  62. type CSS1Parser struct {
  63. *peg.Parser
  64. }
  65. type CSS1Result struct {
  66. * peg.Ast
  67. }
  68. func parserCheck(err error) {
  69. if perr, ok := err.(*peg.Error); ok {
  70. for _, d := range perr.Details {
  71. fmt.Println(d)
  72. }
  73. os.Exit(1)
  74. }
  75. }
  76. /** Creates a CS1 PEG parser. */
  77. func NewCSS1Parser() (*CSS1Parser, error) {
  78. result := &CSS1Parser{}
  79. var err error
  80. result.Parser, err = peg.NewParser(CSS1PEG)
  81. if err == nil {
  82. result.EnableAst()
  83. }
  84. return result, err
  85. }
  86. var defaultCSS1Parser * CSS1Parser
  87. func InitDefaultParser() error {
  88. var err error
  89. defaultCSS1Parser, err = NewCSS1Parser()
  90. return err
  91. }
  92. func wrapResult(wrapme peg.Any) *CSS1Result {
  93. result := &CSS1Result{};
  94. ast, ok := wrapme.(*peg.Ast)
  95. if ok {
  96. result.Ast = ast
  97. return result
  98. }
  99. return nil
  100. }
  101. func (parser CSS1Parser) Parse(source string) (*CSS1Result, error) {
  102. ast, err := parser.ParseAndGetValue(source, nil)
  103. return wrapResult(ast), err
  104. }
  105. func (parser CSS1Parser) ParseFile(filename string) (*CSS1Result, error) {
  106. source, err := ioutil.ReadFile(filename)
  107. if err == nil {
  108. return parser.Parse(string(source))
  109. } else {
  110. return nil, err
  111. }
  112. }
  113. func (css1 CSS1Result) InitializeTheme(theme * Theme) {
  114. }
  115. func parse(source string) (*CSS1Result, error) {
  116. if defaultCSS1Parser == nil {
  117. return nil, errors.New("Default parser not initialized!")
  118. }
  119. return defaultCSS1Parser.Parse(source)
  120. }
  121. func parseFile(filename string) (*CSS1Result, error) {
  122. if defaultCSS1Parser == nil {
  123. return nil, errors.New("Default parser not initialized!")
  124. }
  125. return defaultCSS1Parser.ParseFile(filename)
  126. }