Парсеры для чайников

Парсеры для чайников

@tonyganch

CSScomb

github.com/csscomb
             .a,  .b,
               .c{
            color: tomato;width:100px;
            height:auto}
        
            .a, .b, .c {
                width: 100px;
                height: auto;
                color: tomato;
            }
        
            Success story:
              - препроцессоры
              - php  js
              - регулярные выражения  парсер
        
              1. Парсеры  
              2. Как работают  
              3. Что выбрать  
              4. Как написать  
        

Инструменты разработчика

  1. Препроцессоры: Sass, Stylus, CoffeeScript

Инструменты разработчика

  1. Препроцессоры: Sass, Stylus, CoffeeScript
  2. Оптимизаторы: CSSO, UglifyJS
  3. Линтеры: CSScomb, JSCS, JSHint
  4. Постпроцессоры
  5. Украшатели
  6. Плагины для систем сборки и текстовых редакторов
  7. Автодополнение кода
p { color: white }
               p
               
             color 
               
             white
        
                 p
                 
              background  
                 
               white
        
p { background: white }

p { color: white }

p { background: white }

             строка        дерево   
                                  
             строка        дерево   
        
             строка        дерево   
                                   
             строка        дерево   
        
             строка        дерево   
                                  
             строка        дерево   
        
              1. Парсеры  
              2. Как работают  
              3. Что выбрать  
              4. Как написать  
        
            .panda {
                color: black-and-white;
            }
        
            function getPanda() {
                return this.panda;
            }
        
строка дерево
/* A comment describing the ruleset.*/ .selector-1,.selector-2,.selector-3[type="text"] { box-sizing: border-box; display: block; margin: 0; color: #333; background: #fff; } /* A longer comment describing this ruleset. */ .selector-4, .selector-5 { padding: 10px; } /* This logical grouping of rulesets has no interleaving blank lines. */ .profile { margin: 0; }
/* A comment describing the ruleset.*/ .selector-1,.selector-2,.selector-3[type="text"] { box-sizing: border-box; display: block; margin: 0; color: #333; background: #fff; } /* A longer comment describing this ruleset. */ .selector-4, .selector-5 { padding: 10px; } /* This logical grouping of rulesets has no interleaving blank lines. */ .profile { margin: 0; }
.selector-1,.selector-2,.selector-3[type="text"] { box-sizing: border-box; display: block; margin: 0; color: #333; background: #fff; } .selector-4, .selector-5 { padding: 10px; } .profile { margin: 0; }
                             документ      
                                      
            комментарий  текст  комментарий  текст
        
            [
              {
                type: 'comment',
                start: 0,
                end: 12
              },
              {
                type: 'text',
                start: 13,
                end: 32
              }
            ]
        
            [
              {
                type: 'comment',
                start: 0,
                end: 12
              },
              {
                type: 'text',
                start: 13,
                end: 32
              }
            ]
        
            Парсер:
              1. читает символы
              2. группирует по правилам
        
/* Comment */
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
            p {
              /* Comment */
              color: white; / Comment */
            }
        
                     документ    
                              
            текст  комментарий  текст
        
            function parse(string) {
              var tree = [], node;
             
              for (var i = 0; i < string.length; i++;) {
                node = getComment(i) || getText(i);
                tree.push(node);
                i += node.value.length;
              }
             
              return tree;
            }
        
            function getComment(i) {
                if (string.indexOf('/*', i) !== i) return;
             
                var end = string.indexOf('*/', i + 2) + 1;
                var value = string.splice(i, end);
             
                return createNode('comment', value);
            }
        
            [{
              type: 'text',
              value: 'p {\n  '
            }, {
              type: 'comment',
              value: '/* Comment */'
            }, {
              type: 'text',
              value: '\n  color: white; / Comment */\n}' },
            }]
    

Токены

            пробелы
            комментарии
            идентификаторы
            знаки препинания
        
строка токены дерево
парные скобки
[^};]*?{((([^\{\}]+)|(?R))*)}
            [^};]*?
            {(
              (
                ([^\{\}]+)
                |
                (?R)
              )*
            )}
        
            [^};]*?
            {(
              (
                ([^\{\}]+)
                |
                (?R)
              )*
            )}
        
            {
              type: 'leftCurlyBrace',
              matchingBrace: 12
            }
        

Дерево

            Дерево:
              - дерево разбора
                (parse tree)
              - AST
                (abstract syntax tree)
        
            AST не сохраняет:
              - пробелы
              - знаки препинаний: ; ,
              - ключевые слова: function if
        
                        функция
                              
             аргументы           тело
                               
            x       y          выражение
                                      
                       присвоение      присвоение
                                        
                       x       5       y       10
        
            function (x, y) {
                x = 5, y = 10;
            }
        
            function (x, y) {
                x = 5, y = 10;
            }
        
            function (x, y) {
                x = 5, y = 10;
            }
        
                        функция
                              
             аргументы           тело
                               
            x       y          выражение
                                      
                       присвоение      присвоение
                                        
                       x       5       y       10
        
            function (x, y) {
                x = 5, y = 10;
            }
        
            (x, y) ->
                x = 5
                y = 10
        
             строка 
                      
                         parse tree
                      
             строка 
        
             строка 
                      
                         AST       
                      
             строка 
        
              1. Парсеры  
              2. Как работают  
              3. Что выбрать  
              4. Как написать  
        

Ometa
tinlizzie.org/ometa-js

Jison
github.com/zaach/jison

PEG.js
github.com/dmajda/pegjs

Esprima

github.com/ariya/esprima

Acorn

github.com/marijnh/acorn

Mozilla Parser API

developer.mozilla.org/en-US/docs/
Mozilla/Projects/SpiderMonkey/Parser_API

UglifyJS

github.com/mishoo/UglifyJS2

PostCSS

github.com/ai/postcss

CSS

github.com/reworkcss/css

Gonzales

github.com/css/gonzales

Gonzales PE

github.com/tonyganch/gonzales-pe

Формат дерева

CSSOM

github.com/NV/CSSOM

            .panda {
                color: white;
                color: black;
            }
        
            .panda {color:white}
            .panda       {   color:  white  ; }
        
            [
              {
                start: 12,
                end: 14,
                line: 2,
              }, {
                start: 27,
                end: 38,
                line: 2
              }
            ]
        
            ✓ PostCSS        ✗ CSSOM
            ✓ Gonzales       ✗ CSS
        

Скорость

            меньше деталей —
            выше скорость
        

API

            css.eachDecl(function (decl) {
              decl.parent.prepend(decl.clone());
            });
        
            API:
              - как часть парсера (PostCSS)
              - как отдельный модуль (Gonzales AST)
             
    

Препроцессоры

            .panda
                color white
        
            color()
                color black
             
            .panda
                color white
        
              1. Парсеры  
              2. Как работают  
              3. Что выбрать  
              4. Как написать  
        

Форк

форк = экономия
Gonzales

Gonzales PE

github.com/tonyganch/gonzales-pe

               Gonzales      LESS, SCSS,
                                Sass
                          
                   Gonzales PE
        

Спецификации

CSSOM

dev.w3.org/csswg/cssom

ECMAScript

ecma-international.org/publications/
standards/Ecma-262.htm

Препроцессоры

coffeescript.org

sass-lang.com/documentation

lesscss.org/features

learnboost.github.io/stylus

Тесты

W3C ≠ реальность
            .panda {
                color/*\**/: white\9;
            }
        
            

@media \0screen\,screen\9 {} .panda { [;color: white;]; } .panda { )color: white; } .panda { =color: white; }

browserhacks.com

            @media \0screen\,screen\9 {}
            .panda { [;color: white;]; }
            .panda { )color: white; }
            .panda { =color: white; }
        

jquery.com

getbootstrap.com

yuilibrary.com

            github.com/search
        

* * *

строка дерево
строка токены дерево
            Парсер:
              - читает символы
              - группирует по правилам
        
            Дерево:
              - parse tree
              - AST
        
            AST не сохраняет:
              - пробелы
              - знаки препинаний
              - ключевые слова
        
            При выборе смотрите на:
              - формат дерева
              - скорость
              - API
              - препроцессоры
        
форки = хорошо
спецификации = хорошо
            @media \0screen\,screen\9 {}
            .panda { [;color: white;]; }
            .panda { )color: white; }
            .panda { =color: white; }
        
                       @tonyganch
             
                       Gonzales PE
            github.com/tonyganch/gonzales-pe