Add more selectors and property values

This commit is contained in:
Max Brunsfeld 2018-10-17 23:14:21 -07:00
parent 0b7b855822
commit c3ffccdac1
8 changed files with 2592 additions and 945 deletions

View File

@ -8,6 +8,7 @@
],
"sources": [
"src/parser.c",
"src/scanner.c",
"src/binding.cc"
],
"cflags_c": [

View File

@ -5,3 +5,17 @@ Functions
a {
color: rgba(0, 255, 0, 0.5);
}
---
(stylesheet
(rule_set
(selectors (tag_name))
(block
(declaration
(property_name)
(function_value (function_name) (arguments
(integer_value)
(integer_value)
(integer_value)
(float_value)))))))

View File

@ -18,31 +18,39 @@ div, span {}
---
(stylesheet
(rule_set (selectors (type_selector (identifier)) (type_selector (identifier))) (block)))
(rule_set (selectors (tag_name) (tag_name)) (block)))
=========================
Class selectors
=========================
.class-a {}
.class-b, .class-c {}
div.class-b, .class-c.class-d {}
---
(stylesheet
(rule_set (selectors (class_selector (identifier))) (block))
(rule_set (selectors (class_selector (identifier)) (class_selector (identifier))) (block)))
(rule_set
(selectors (class_selector (class_name)))
(block))
(rule_set
(selectors
(class_selector (tag_name) (class_name))
(class_selector (class_selector (class_name)) (class_name)))
(block)))
=========================
Id selectors
=========================
#some-id {}
#some-id, a#another-id {}
---
(stylesheet
(rule_set (selectors (id_selector (identifier))) (block)))
(rule_set
(selectors (id_selector (id_name)) (id_selector (tag_name) (id_name)))
(block)))
=========================
Attribute selectors
@ -51,13 +59,45 @@ Attribute selectors
[a] {}
[b=c] {}
[d~=e] {}
a[b] {}
---
(stylesheet
(rule_set (selectors (attribute_selector (property_name (identifier)))) (block))
(rule_set (selectors (attribute_selector (property_name (identifier)) (property_value))) (block))
(rule_set (selectors (attribute_selector (property_name (identifier)) (property_value))) (block)))
(rule_set (selectors (attribute_selector (attribute_name))) (block))
(rule_set (selectors (attribute_selector (attribute_name) (value_name))) (block))
(rule_set (selectors (attribute_selector (attribute_name) (value_name))) (block))
(rule_set (selectors (attribute_selector (tag_name) (attribute_name))) (block)))
=========================
Pseudo-class selectors
=========================
a:hover {}
:nth-child(2) {}
---
(stylesheet
(rule_set
(selectors (pseudo_class_selector (tag_name) (class_name)))
(block))
(rule_set
(selectors (pseudo_class_selector (class_name) (arguments (integer_value))))
(block)))
=========================
Pseudo-element selectors
=========================
a::first-line {}
---
(stylesheet
(rule_set
(selectors (pseudo_element_selector (tag_name) (tag_name)))
(block)))
=========================
Child selectors
@ -70,12 +110,12 @@ c > d > e {}
(stylesheet
(rule_set
(selectors (child_selector (type_selector (identifier)) (type_selector (identifier))))
(selectors (child_selector (tag_name) (tag_name)))
(block))
(rule_set
(selectors (child_selector
(child_selector (type_selector (identifier)) (type_selector (identifier)))
(type_selector (identifier))))
(child_selector (tag_name) (tag_name))
(tag_name)))
(block)))
=========================
@ -89,10 +129,30 @@ c d e {}
(stylesheet
(rule_set
(selectors (descendant_selector (type_selector (identifier)) (type_selector (identifier))))
(selectors (descendant_selector (tag_name) (tag_name)))
(block))
(rule_set
(selectors (descendant_selector
(descendant_selector (type_selector (identifier)) (type_selector (identifier)))
(type_selector (identifier))))
(descendant_selector (tag_name) (tag_name))
(tag_name)))
(block)))
===========================
Nesting selectors
===========================
a {
&.b {}
& c {}
& > d {}
}
---
(stylesheet
(rule_set
(selectors (tag_name))
(block
(rule_set (selectors (class_selector (nesting_selector) (class_name))) (block))
(rule_set (selectors (descendant_selector (nesting_selector) (tag_name))) (block))
(rule_set (selectors (child_selector (nesting_selector) (tag_name))) (block)))))

View File

@ -10,6 +10,6 @@ Rule sets
(stylesheet
(rule_set
(selectors (id_selector (identifier)))
(selectors (id_selector (id_name)))
(block
(declaration (property_name (identifier)) (property_value)))))
(declaration (property_name) (integer_value (unit))))))

View File

@ -6,6 +6,10 @@ module.exports = grammar({
$.comment,
],
externals: $ => [
$._descendant_operator,
],
rules: {
stylesheet: $ => repeat(choice(
$.rule_set,
@ -27,60 +31,130 @@ module.exports = grammar({
selectors: $ => commaSep1($._selector),
block: $ => seq('{', repeat($.declaration), '}'),
block: $ => seq(
'{',
repeat(choice($.declaration, $.rule_set)),
'}'
),
// Selectors
_selector: $ => choice(
$.universal_selector,
$.type_selector,
alias($.identifier, $.tag_name),
$.class_selector,
$.nesting_selector,
$.pseudo_class_selector,
$.pseudo_element_selector,
$.id_selector,
$.attribute_selector,
$.child_selector,
$.descendant_selector
),
nesting_selector: $ => '&',
universal_selector: $ => '*',
type_selector: $ => $.identifier,
class_selector: $ => seq(
optional($._selector),
'.',
alias($.identifier, $.class_name),
),
class_selector: $ => seq('.', $.identifier),
pseudo_class_selector: $ => seq(
optional($._selector),
':',
alias($.identifier, $.class_name),
optional($.arguments)
),
id_selector: $ => seq('#', $.identifier),
pseudo_element_selector: $ => seq(
optional($._selector),
'::',
alias($.identifier, $.tag_name)
),
id_selector: $ => seq(
optional($._selector),
'#',
alias($.identifier, $.id_name)
),
attribute_selector: $ => seq(
choice(
'[',
seq($._selector, token.immediate('['))
),
$.property_name,
optional($._selector),
'[',
alias($.identifier, $.attribute_name),
optional(seq(
choice('=', '~=', '^=', '|=', '*=', '$='),
$.property_value
$._value
)),
']'
),
child_selector: $ => prec.left(seq($._selector, '>', $._selector)),
descendant_selector: $ => prec.left(seq($._selector, $._selector)),
descendant_selector: $ => prec.left(seq($._selector, $._descendant_operator, $._selector)),
// Declarations
declaration: $ => seq(
$.property_name,
declaration: $ => prec(1, seq(
alias($.identifier, $.property_name),
':',
$.property_value,
repeat1($._value),
';'
)),
// Property Values
_value: $ => choice(
alias($.identifier, $.value_name),
$.color_value,
$.integer_value,
$.float_value,
$.function_value
),
integer_value: $ => seq(
token(seq(
optional(choice('+', '-')),
/\d+/
)),
optional($.unit)
),
float_value: $ => seq(
token(seq(
optional(choice('+', '-')),
/\d*/,
choice(
seq('.', /\d+/),
seq('e', optional('-'), /\d+/),
seq('.', /\d+/, 'e', optional('-'), /\d+/)
)
)),
optional($.unit)
),
unit: $ => token.immediate(/[a-z]+/),
color_value: $ => /#[0-9a-fA-F]{3,6}/,
function_value: $ => seq(
alias($.identifier, $.function_name),
$.arguments
),
arguments: $ => seq(
'(',
commaSep($._value),
')'
),
property_name: $ => $.identifier,
identifier: $ => /[a-zA-Z-_]+/,
property_value: $ => /[^;()\[\]]+/,
comment: $ => token(choice(
seq('//', /.*/),
seq(
@ -92,6 +166,10 @@ module.exports = grammar({
}
})
function commaSep (rule) {
return optional(commaSep1(rule))
}
function commaSep1 (rule) {
return seq(rule, repeat(seq(',', rule)))
}

510
src/grammar.json vendored
View File

@ -74,8 +74,17 @@
{
"type": "REPEAT",
"content": {
"type": "SYMBOL",
"name": "declaration"
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "declaration"
},
{
"type": "SYMBOL",
"name": "rule_set"
}
]
}
},
{
@ -92,13 +101,30 @@
"name": "universal_selector"
},
{
"type": "SYMBOL",
"name": "type_selector"
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "identifier"
},
"named": true,
"value": "tag_name"
},
{
"type": "SYMBOL",
"name": "class_selector"
},
{
"type": "SYMBOL",
"name": "nesting_selector"
},
{
"type": "SYMBOL",
"name": "pseudo_class_selector"
},
{
"type": "SYMBOL",
"name": "pseudo_element_selector"
},
{
"type": "SYMBOL",
"name": "id_selector"
@ -117,37 +143,143 @@
}
]
},
"nesting_selector": {
"type": "STRING",
"value": "&"
},
"universal_selector": {
"type": "STRING",
"value": "*"
},
"type_selector": {
"type": "SYMBOL",
"name": "identifier"
},
"class_selector": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_selector"
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "."
},
{
"type": "SYMBOL",
"name": "identifier"
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "identifier"
},
"named": true,
"value": "class_name"
}
]
},
"pseudo_class_selector": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_selector"
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": ":"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "identifier"
},
"named": true,
"value": "class_name"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "arguments"
},
{
"type": "BLANK"
}
]
}
]
},
"pseudo_element_selector": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_selector"
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "::"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "identifier"
},
"named": true,
"value": "tag_name"
}
]
},
"id_selector": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_selector"
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "#"
},
{
"type": "SYMBOL",
"name": "identifier"
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "identifier"
},
"named": true,
"value": "id_name"
}
]
},
@ -158,30 +290,26 @@
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "["
"type": "SYMBOL",
"name": "_selector"
},
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_selector"
},
{
"type": "IMMEDIATE_TOKEN",
"content": {
"type": "STRING",
"value": "["
}
}
]
"type": "BLANK"
}
]
},
{
"type": "SYMBOL",
"name": "property_name"
"type": "STRING",
"value": "["
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "identifier"
},
"named": true,
"value": "attribute_name"
},
{
"type": "CHOICE",
@ -220,7 +348,7 @@
},
{
"type": "SYMBOL",
"name": "property_value"
"name": "_value"
}
]
},
@ -266,6 +394,10 @@
"type": "SYMBOL",
"name": "_selector"
},
{
"type": "SYMBOL",
"name": "_descendant_operator"
},
{
"type": "SYMBOL",
"name": "_selector"
@ -274,23 +406,316 @@
}
},
"declaration": {
"type": "PREC",
"value": 1,
"content": {
"type": "SEQ",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "identifier"
},
"named": true,
"value": "property_name"
},
{
"type": "STRING",
"value": ":"
},
{
"type": "REPEAT1",
"content": {
"type": "SYMBOL",
"name": "_value"
}
},
{
"type": "STRING",
"value": ";"
}
]
}
},
"_value": {
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "identifier"
},
"named": true,
"value": "value_name"
},
{
"type": "SYMBOL",
"name": "color_value"
},
{
"type": "SYMBOL",
"name": "integer_value"
},
{
"type": "SYMBOL",
"name": "float_value"
},
{
"type": "SYMBOL",
"name": "function_value"
}
]
},
"integer_value": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "property_name"
"type": "TOKEN",
"content": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "+"
},
{
"type": "STRING",
"value": "-"
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "PATTERN",
"value": "\\d+"
}
]
}
},
{
"type": "STRING",
"value": ":"
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "unit"
},
{
"type": "BLANK"
}
]
}
]
},
"float_value": {
"type": "SEQ",
"members": [
{
"type": "TOKEN",
"content": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "+"
},
{
"type": "STRING",
"value": "-"
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "PATTERN",
"value": "\\d*"
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "."
},
{
"type": "PATTERN",
"value": "\\d+"
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "e"
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "-"
},
{
"type": "BLANK"
}
]
},
{
"type": "PATTERN",
"value": "\\d+"
}
]
},
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "."
},
{
"type": "PATTERN",
"value": "\\d+"
},
{
"type": "STRING",
"value": "e"
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "-"
},
{
"type": "BLANK"
}
]
},
{
"type": "PATTERN",
"value": "\\d+"
}
]
}
]
}
]
}
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "unit"
},
{
"type": "BLANK"
}
]
}
]
},
"unit": {
"type": "IMMEDIATE_TOKEN",
"content": {
"type": "PATTERN",
"value": "[a-z]+"
}
},
"color_value": {
"type": "PATTERN",
"value": "#[0-9a-fA-F]{3,6}"
},
"function_value": {
"type": "SEQ",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "identifier"
},
"named": true,
"value": "function_name"
},
{
"type": "SYMBOL",
"name": "property_value"
"name": "arguments"
}
]
},
"arguments": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "("
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_value"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "_value"
}
]
}
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": ";"
"value": ")"
}
]
},
@ -302,10 +727,6 @@
"type": "PATTERN",
"value": "[a-zA-Z-_]+"
},
"property_value": {
"type": "PATTERN",
"value": "[^;()\\[\\]]+"
},
"comment": {
"type": "TOKEN",
"content": {
@ -356,6 +777,11 @@
}
],
"conflicts": [],
"externals": [],
"externals": [
{
"type": "SYMBOL",
"name": "_descendant_operator"
}
],
"inline": []
}

2770
src/parser.c vendored

File diff suppressed because it is too large Load Diff

36
src/scanner.c vendored Normal file
View File

@ -0,0 +1,36 @@
#include <tree_sitter/parser.h>
#include <wctype.h>
enum TokenType {
DESCENDANT_OP,
};
void *tree_sitter_css_external_scanner_create() { return NULL; }
void tree_sitter_css_external_scanner_destroy(void *p) {}
void tree_sitter_css_external_scanner_reset(void *p) {}
unsigned tree_sitter_css_external_scanner_serialize(void *p, char *buffer) { return 0; }
void tree_sitter_css_external_scanner_deserialize(void *p, const char *b, unsigned n) {}
bool tree_sitter_css_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) {
if (iswspace(lexer->lookahead)) {
lexer->advance(lexer, true);
while (iswspace(lexer->lookahead)) {
lexer->advance(lexer, true);
}
if (
lexer->lookahead == '#' ||
lexer->lookahead == '.' ||
lexer->lookahead == '[' ||
lexer->lookahead == ':' ||
lexer->lookahead == '-' ||
iswalnum(lexer->lookahead)
) {
lexer->result_symbol = DESCENDANT_OP;
return true;
}
}
return false;
}