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": [ "sources": [
"src/parser.c", "src/parser.c",
"src/scanner.c",
"src/binding.cc" "src/binding.cc"
], ],
"cflags_c": [ "cflags_c": [

View File

@ -5,3 +5,17 @@ Functions
a { a {
color: rgba(0, 255, 0, 0.5); 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 (stylesheet
(rule_set (selectors (type_selector (identifier)) (type_selector (identifier))) (block))) (rule_set (selectors (tag_name) (tag_name)) (block)))
========================= =========================
Class selectors Class selectors
========================= =========================
.class-a {} .class-a {}
.class-b, .class-c {} div.class-b, .class-c.class-d {}
--- ---
(stylesheet (stylesheet
(rule_set (selectors (class_selector (identifier))) (block)) (rule_set
(rule_set (selectors (class_selector (identifier)) (class_selector (identifier))) (block))) (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 Id selectors
========================= =========================
#some-id {} #some-id, a#another-id {}
--- ---
(stylesheet (stylesheet
(rule_set (selectors (id_selector (identifier))) (block))) (rule_set
(selectors (id_selector (id_name)) (id_selector (tag_name) (id_name)))
(block)))
========================= =========================
Attribute selectors Attribute selectors
@ -51,13 +59,45 @@ Attribute selectors
[a] {} [a] {}
[b=c] {} [b=c] {}
[d~=e] {} [d~=e] {}
a[b] {}
--- ---
(stylesheet (stylesheet
(rule_set (selectors (attribute_selector (property_name (identifier)))) (block)) (rule_set (selectors (attribute_selector (attribute_name))) (block))
(rule_set (selectors (attribute_selector (property_name (identifier)) (property_value))) (block)) (rule_set (selectors (attribute_selector (attribute_name) (value_name))) (block))
(rule_set (selectors (attribute_selector (property_name (identifier)) (property_value))) (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 Child selectors
@ -70,12 +110,12 @@ c > d > e {}
(stylesheet (stylesheet
(rule_set (rule_set
(selectors (child_selector (type_selector (identifier)) (type_selector (identifier)))) (selectors (child_selector (tag_name) (tag_name)))
(block)) (block))
(rule_set (rule_set
(selectors (child_selector (selectors (child_selector
(child_selector (type_selector (identifier)) (type_selector (identifier))) (child_selector (tag_name) (tag_name))
(type_selector (identifier)))) (tag_name)))
(block))) (block)))
========================= =========================
@ -89,10 +129,30 @@ c d e {}
(stylesheet (stylesheet
(rule_set (rule_set
(selectors (descendant_selector (type_selector (identifier)) (type_selector (identifier)))) (selectors (descendant_selector (tag_name) (tag_name)))
(block)) (block))
(rule_set (rule_set
(selectors (descendant_selector (selectors (descendant_selector
(descendant_selector (type_selector (identifier)) (type_selector (identifier))) (descendant_selector (tag_name) (tag_name))
(type_selector (identifier)))) (tag_name)))
(block))) (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 (stylesheet
(rule_set (rule_set
(selectors (id_selector (identifier))) (selectors (id_selector (id_name)))
(block (block
(declaration (property_name (identifier)) (property_value))))) (declaration (property_name) (integer_value (unit))))))

View File

@ -6,6 +6,10 @@ module.exports = grammar({
$.comment, $.comment,
], ],
externals: $ => [
$._descendant_operator,
],
rules: { rules: {
stylesheet: $ => repeat(choice( stylesheet: $ => repeat(choice(
$.rule_set, $.rule_set,
@ -27,60 +31,130 @@ module.exports = grammar({
selectors: $ => commaSep1($._selector), selectors: $ => commaSep1($._selector),
block: $ => seq('{', repeat($.declaration), '}'), block: $ => seq(
'{',
repeat(choice($.declaration, $.rule_set)),
'}'
),
// Selectors // Selectors
_selector: $ => choice( _selector: $ => choice(
$.universal_selector, $.universal_selector,
$.type_selector, alias($.identifier, $.tag_name),
$.class_selector, $.class_selector,
$.nesting_selector,
$.pseudo_class_selector,
$.pseudo_element_selector,
$.id_selector, $.id_selector,
$.attribute_selector, $.attribute_selector,
$.child_selector, $.child_selector,
$.descendant_selector $.descendant_selector
), ),
nesting_selector: $ => '&',
universal_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( attribute_selector: $ => seq(
choice( optional($._selector),
'[', '[',
seq($._selector, token.immediate('[')) alias($.identifier, $.attribute_name),
),
$.property_name,
optional(seq( optional(seq(
choice('=', '~=', '^=', '|=', '*=', '$='), choice('=', '~=', '^=', '|=', '*=', '$='),
$.property_value $._value
)), )),
']' ']'
), ),
child_selector: $ => prec.left(seq($._selector, '>', $._selector)), child_selector: $ => prec.left(seq($._selector, '>', $._selector)),
descendant_selector: $ => prec.left(seq($._selector, $._selector)), descendant_selector: $ => prec.left(seq($._selector, $._descendant_operator, $._selector)),
// Declarations // Declarations
declaration: $ => seq( declaration: $ => prec(1, seq(
$.property_name, 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, property_name: $ => $.identifier,
identifier: $ => /[a-zA-Z-_]+/, identifier: $ => /[a-zA-Z-_]+/,
property_value: $ => /[^;()\[\]]+/,
comment: $ => token(choice( comment: $ => token(choice(
seq('//', /.*/), seq('//', /.*/),
seq( seq(
@ -92,6 +166,10 @@ module.exports = grammar({
} }
}) })
function commaSep (rule) {
return optional(commaSep1(rule))
}
function commaSep1 (rule) { function commaSep1 (rule) {
return seq(rule, repeat(seq(',', rule))) return seq(rule, repeat(seq(',', rule)))
} }

482
src/grammar.json vendored
View File

@ -74,8 +74,17 @@
{ {
"type": "REPEAT", "type": "REPEAT",
"content": { "content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL", "type": "SYMBOL",
"name": "declaration" "name": "declaration"
},
{
"type": "SYMBOL",
"name": "rule_set"
}
]
} }
}, },
{ {
@ -92,13 +101,30 @@
"name": "universal_selector" "name": "universal_selector"
}, },
{ {
"type": "ALIAS",
"content": {
"type": "SYMBOL", "type": "SYMBOL",
"name": "type_selector" "name": "identifier"
},
"named": true,
"value": "tag_name"
}, },
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "class_selector" "name": "class_selector"
}, },
{
"type": "SYMBOL",
"name": "nesting_selector"
},
{
"type": "SYMBOL",
"name": "pseudo_class_selector"
},
{
"type": "SYMBOL",
"name": "pseudo_element_selector"
},
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "id_selector" "name": "id_selector"
@ -117,37 +143,143 @@
} }
] ]
}, },
"nesting_selector": {
"type": "STRING",
"value": "&"
},
"universal_selector": { "universal_selector": {
"type": "STRING", "type": "STRING",
"value": "*" "value": "*"
}, },
"type_selector": {
"type": "SYMBOL",
"name": "identifier"
},
"class_selector": { "class_selector": {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_selector"
},
{
"type": "BLANK"
}
]
},
{ {
"type": "STRING", "type": "STRING",
"value": "." "value": "."
}, },
{ {
"type": "ALIAS",
"content": {
"type": "SYMBOL", "type": "SYMBOL",
"name": "identifier" "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": { "id_selector": {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "_selector"
},
{
"type": "BLANK"
}
]
},
{ {
"type": "STRING", "type": "STRING",
"value": "#" "value": "#"
}, },
{ {
"type": "ALIAS",
"content": {
"type": "SYMBOL", "type": "SYMBOL",
"name": "identifier" "name": "identifier"
},
"named": true,
"value": "id_name"
} }
] ]
}, },
@ -156,32 +288,28 @@
"members": [ "members": [
{ {
"type": "CHOICE", "type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "["
},
{
"type": "SEQ",
"members": [ "members": [
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "_selector" "name": "_selector"
}, },
{ {
"type": "IMMEDIATE_TOKEN", "type": "BLANK"
"content": {
"type": "STRING",
"value": "["
}
}
]
} }
] ]
}, },
{ {
"type": "STRING",
"value": "["
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL", "type": "SYMBOL",
"name": "property_name" "name": "identifier"
},
"named": true,
"value": "attribute_name"
}, },
{ {
"type": "CHOICE", "type": "CHOICE",
@ -220,7 +348,7 @@
}, },
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "property_value" "name": "_value"
} }
] ]
}, },
@ -266,6 +394,10 @@
"type": "SYMBOL", "type": "SYMBOL",
"name": "_selector" "name": "_selector"
}, },
{
"type": "SYMBOL",
"name": "_descendant_operator"
},
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "_selector" "name": "_selector"
@ -274,25 +406,318 @@
} }
}, },
"declaration": { "declaration": {
"type": "PREC",
"value": 1,
"content": {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
{ {
"type": "ALIAS",
"content": {
"type": "SYMBOL", "type": "SYMBOL",
"name": "property_name" "name": "identifier"
},
"named": true,
"value": "property_name"
}, },
{ {
"type": "STRING", "type": "STRING",
"value": ":" "value": ":"
}, },
{ {
"type": "REPEAT1",
"content": {
"type": "SYMBOL", "type": "SYMBOL",
"name": "property_value" "name": "_value"
}
}, },
{ {
"type": "STRING", "type": "STRING",
"value": ";" "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": "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": "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": "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": ")"
}
]
}, },
"property_name": { "property_name": {
"type": "SYMBOL", "type": "SYMBOL",
@ -302,10 +727,6 @@
"type": "PATTERN", "type": "PATTERN",
"value": "[a-zA-Z-_]+" "value": "[a-zA-Z-_]+"
}, },
"property_value": {
"type": "PATTERN",
"value": "[^;()\\[\\]]+"
},
"comment": { "comment": {
"type": "TOKEN", "type": "TOKEN",
"content": { "content": {
@ -356,6 +777,11 @@
} }
], ],
"conflicts": [], "conflicts": [],
"externals": [], "externals": [
{
"type": "SYMBOL",
"name": "_descendant_operator"
}
],
"inline": [] "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;
}