|
@@ -0,0 +1,149 @@
|
|
|
+package style
|
|
|
+
|
|
|
+import "github.com/yhirose/go-peg"
|
|
|
+import "fmt"
|
|
|
+import "os"
|
|
|
+import "io/ioutil"
|
|
|
+import "errors"
|
|
|
+
|
|
|
+const CSS1PEG =
|
|
|
+`
|
|
|
+# CSS1 parser for a PEG parser generator.
|
|
|
+# and a user command parser
|
|
|
+# Doesn't support import statements.
|
|
|
+
|
|
|
+
|
|
|
+STYLESHEET ← (CDO / CDC)* (RULESET/DECLARATIONS/COMMENT/ATRULE)* (CDO / CDC)*
|
|
|
+RULESET ← SELECTORS "{" DECLARATIONS? "}"
|
|
|
+SELECTORS ← SELECTOR ("," SELECTOR)*
|
|
|
+SELECTOR ← ( "*" / NAME ID? CLASS? PSEUDO_CLASS? /
|
|
|
+ ID CLASS? PSEUDO_CLASS? /
|
|
|
+ CLASS PSEUDO_CLASS? /
|
|
|
+ PSEUDO_CLASS )+ PSEUDO_ELEMENT* / PSEUDO_ELEMENT
|
|
|
+ATRULE ← ATID (STRING / URL) ";" / ATID "{" DECLARATIONS "}"
|
|
|
+NAME ← <IDENT>
|
|
|
+DECLARATIONS ← DECLARATION (';' DECLARATION)* ';'?
|
|
|
+DECLARATION ← NAME ":" EXPR PRIO? / COMMENT
|
|
|
+OPERATOR ← '/' / ','
|
|
|
+# UNARY_OPERATOR ← '-' / '+'
|
|
|
+PRIO ← IMPORTANT
|
|
|
+EXPR ← TERM (OPERATOR TERM)*
|
|
|
+TERM ← STRING / PERCENTAGE / LENGTH / HEXCOLOR / URL / RGB / NUM / IDENT
|
|
|
+~COMMENT ← "/*" (!("*/").)* "*/"
|
|
|
+ATID ← < "@" [a-zA-Z][-_a-zA-Z0-9]+ >
|
|
|
+IMPORTANT ← < "!" WS "important" >
|
|
|
+IDENT ← < [-_a-zA-Z][-_a-zA-Z0-9]* >
|
|
|
+PERCENTAGE ← < NUM > "%"
|
|
|
+NUM ← < [+-]*[0-9]+ / [0-9]* "." [0-9]+ >
|
|
|
+LENGTH ← NUM UNIT
|
|
|
+UNIT ← <"pt" / "mm" / "pt" / "in" / "px" / "em" / "ex" >
|
|
|
+PSEUDO_ELEMENT ← <":first-letter" / ":first-line" >
|
|
|
+PSEUDO_CLASS ← <":hover" / ":link" / ":mark" / ":active" / ":visited" >
|
|
|
+HEXCOLOR ← "#" < ([0-9a-fA-F])+ >
|
|
|
+ID ← "#" < IDENT >
|
|
|
+CLASS ← "." < IDENT >
|
|
|
+
|
|
|
+# Raw string macro.
|
|
|
+RAWSM(O,C) ← O < (!(C).)* > C
|
|
|
+# Escaped string macro.
|
|
|
+ESCSM(O,C) ← O < (!(C)STRCHAR)* > C
|
|
|
+# String escapes
|
|
|
+STRESC1 ← "\\" [nrtfv\'\\"\[\]\\]
|
|
|
+STRESC2 ← "\\" [0-3] [0-7] [0-7]
|
|
|
+STRESC3 ← "\\" [0-7] [0-7]*
|
|
|
+STRESC4 ← "\\x" [0-9a-fA-F] [0-9a-fA-F]?
|
|
|
+STRESC5 ← "\\u" [0-9a-fA-F]+
|
|
|
+STRNOESC ← (!('\\\\').)
|
|
|
+STRCHAR ← STRESC1 / STRESC2 / STRESC3 / STRESC4 / STRESC5 / STRNOESC
|
|
|
+# Strings
|
|
|
+STRING ← ESCSM("\"", "\"") / ESCSM("'", "'")
|
|
|
+URL ← "url(" STRING ")"
|
|
|
+RGB ← < "rgb("[ \t]*[0-9]+[ \t]* "," [ \t]*[0-9]+[ \t]* "," [ \t]*[0-9]+[ \t]* ")" >
|
|
|
+~WS ← [ \t\n\r]*
|
|
|
+CDO ← "<!--"
|
|
|
+CDC ← "-->"
|
|
|
+%whitespace ← [ \t\n\r]*
|
|
|
+`
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+type CSS1Parser struct {
|
|
|
+ *peg.Parser
|
|
|
+}
|
|
|
+
|
|
|
+type CSS1Result struct {
|
|
|
+ * peg.Ast
|
|
|
+}
|
|
|
+
|
|
|
+func parserCheck(err error) {
|
|
|
+ if perr, ok := err.(*peg.Error); ok {
|
|
|
+ for _, d := range perr.Details {
|
|
|
+ fmt.Println(d)
|
|
|
+ }
|
|
|
+ os.Exit(1)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func NewCSS1Parser() (*CSS1Parser, error) {
|
|
|
+ result := &CSS1Parser{}
|
|
|
+ var err error
|
|
|
+ result.Parser, err = peg.NewParser(CSS1PEG)
|
|
|
+ if err == nil {
|
|
|
+ result.EnableAst()
|
|
|
+ }
|
|
|
+ return result, err
|
|
|
+}
|
|
|
+
|
|
|
+var defaultCSS1Parser * CSS1Parser
|
|
|
+
|
|
|
+func InitDefaultParser() error {
|
|
|
+ var err error
|
|
|
+ defaultCSS1Parser, err = NewCSS1Parser()
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+func wrapResult(wrapme peg.Any) *CSS1Result {
|
|
|
+ result := &CSS1Result{};
|
|
|
+ ast, ok := wrapme.(*peg.Ast)
|
|
|
+ if ok {
|
|
|
+ result.Ast = ast
|
|
|
+ return result
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (parser CSS1Parser) Parse(source string) (*CSS1Result, error) {
|
|
|
+ ast, err := parser.ParseAndGetValue(source, nil)
|
|
|
+ return wrapResult(ast), err
|
|
|
+}
|
|
|
+
|
|
|
+func (parser CSS1Parser) ParseFile(filename string) (*CSS1Result, error) {
|
|
|
+ source, err := ioutil.ReadFile(filename)
|
|
|
+ if err == nil {
|
|
|
+ return parser.Parse(string(source))
|
|
|
+ } else {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (css1 CSS1Result) InitializeTheme(theme * Theme) {
|
|
|
+}
|
|
|
+
|
|
|
+func parse(source string) (*CSS1Result, error) {
|
|
|
+ if defaultCSS1Parser == nil {
|
|
|
+ return nil, errors.New("Default parser not initialized!")
|
|
|
+ }
|
|
|
+ return defaultCSS1Parser.Parse(source)
|
|
|
+}
|
|
|
+
|
|
|
+func parseFile(filename string) (*CSS1Result, error) {
|
|
|
+ if defaultCSS1Parser == nil {
|
|
|
+ return nil, errors.New("Default parser not initialized!")
|
|
|
+ }
|
|
|
+ return defaultCSS1Parser.ParseFile(filename)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|