Start work on property sheet compilation
This commit is contained in:
parent
c0fad8b3c4
commit
6bd550ca87
7 changed files with 532 additions and 48 deletions
142
Cargo.lock
generated
142
Cargo.lock
generated
|
|
@ -41,6 +41,11 @@ dependencies = [
|
|||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.9"
|
||||
|
|
@ -336,6 +341,36 @@ name = "nodrop"
|
|||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "4.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.0"
|
||||
|
|
@ -408,6 +443,32 @@ dependencies = [
|
|||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_os 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.2.2"
|
||||
|
|
@ -421,6 +482,60 @@ name = "rand_core"
|
|||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_isaac"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_os"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.43"
|
||||
|
|
@ -465,6 +580,18 @@ dependencies = [
|
|||
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsass"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.14.0"
|
||||
|
|
@ -657,6 +784,7 @@ dependencies = [
|
|||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rsass 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rusqlite 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -756,6 +884,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
|
||||
"checksum arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e5f34df7a019573fb8bdc7e24a2bfebe51a2a1d6bfdbaeccedb3c41fc574727"
|
||||
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
||||
"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
|
|
@ -793,6 +922,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
|
||||
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||
"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
|
||||
"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
|
||||
|
|
@ -801,13 +934,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
|
||||
"checksum rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3906503e80ac6cbcacb2c2973fa8e473f24d7e2747c8c92bb230c2441cad96b5"
|
||||
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||
"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
|
||||
"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
|
||||
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
|
||||
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
|
||||
"checksum rand_os 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46fbd5550acf75b0c2730f5dd1873751daf9beb8f11b44027778fae50d7feca"
|
||||
"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
|
||||
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26"
|
||||
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
|
||||
"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
|
||||
"checksum rsass 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7a5dde55023a6c19470f7aeb59f75f897d8b80cbe00d61dfcaf7bbbe3de4c0a6"
|
||||
"checksum rusqlite 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c9d9118f1ce84d8d0b67f9779936432fb42bb620cef2122409d786892cce9a3c"
|
||||
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ serde = "1.0"
|
|||
serde_derive = "1.0"
|
||||
regex-syntax = "0.6.4"
|
||||
regex = "1"
|
||||
rsass = "0.9"
|
||||
|
||||
[dependencies.tree-sitter]
|
||||
path = "../lib"
|
||||
|
|
|
|||
|
|
@ -31,6 +31,12 @@ impl From<io::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<rsass::Error> for Error {
|
||||
fn from(error: rsass::Error) -> Self {
|
||||
Error(error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Error {
|
||||
fn from(error: String) -> Self {
|
||||
Error(error)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ mod grammars;
|
|||
mod nfa;
|
||||
mod parse_grammar;
|
||||
mod prepare_grammar;
|
||||
mod properties;
|
||||
mod render;
|
||||
mod rules;
|
||||
mod tables;
|
||||
|
|
@ -21,30 +22,34 @@ pub fn generate_parser_for_grammar(
|
|||
repo_path: &PathBuf,
|
||||
minimize: bool,
|
||||
state_ids_to_log: Vec<usize>,
|
||||
properties_only: bool,
|
||||
) -> Result<()> {
|
||||
let grammar_json = load_js_grammar_file(&repo_path.join("grammar.js"));
|
||||
let input_grammar = parse_grammar(&grammar_json)?;
|
||||
let (syntax_grammar, lexical_grammar, inlines, simple_aliases) =
|
||||
prepare_grammar(&input_grammar)?;
|
||||
let (parse_table, main_lex_table, keyword_lex_table, keyword_capture_token) = build_tables(
|
||||
&syntax_grammar,
|
||||
&lexical_grammar,
|
||||
&simple_aliases,
|
||||
&inlines,
|
||||
minimize,
|
||||
state_ids_to_log,
|
||||
)?;
|
||||
let c_code = render_c_code(
|
||||
&input_grammar.name,
|
||||
parse_table,
|
||||
main_lex_table,
|
||||
keyword_lex_table,
|
||||
keyword_capture_token,
|
||||
syntax_grammar,
|
||||
lexical_grammar,
|
||||
simple_aliases,
|
||||
);
|
||||
fs::write(repo_path.join("src").join("parser.c"), c_code)?;
|
||||
if !properties_only {
|
||||
let grammar_json = load_js_grammar_file(&repo_path.join("grammar.js"));
|
||||
let input_grammar = parse_grammar(&grammar_json)?;
|
||||
let (syntax_grammar, lexical_grammar, inlines, simple_aliases) =
|
||||
prepare_grammar(&input_grammar)?;
|
||||
let (parse_table, main_lex_table, keyword_lex_table, keyword_capture_token) = build_tables(
|
||||
&syntax_grammar,
|
||||
&lexical_grammar,
|
||||
&simple_aliases,
|
||||
&inlines,
|
||||
minimize,
|
||||
state_ids_to_log,
|
||||
)?;
|
||||
let c_code = render_c_code(
|
||||
&input_grammar.name,
|
||||
parse_table,
|
||||
main_lex_table,
|
||||
keyword_lex_table,
|
||||
keyword_capture_token,
|
||||
syntax_grammar,
|
||||
lexical_grammar,
|
||||
simple_aliases,
|
||||
);
|
||||
fs::write(repo_path.join("src").join("parser.c"), c_code)?;
|
||||
}
|
||||
properties::generate_property_sheets(repo_path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
327
cli/src/generate/properties.rs
Normal file
327
cli/src/generate/properties.rs
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
use crate::error::{Error, Result};
|
||||
use rsass;
|
||||
use rsass::sass::Value;
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use std::fs::{self, File};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::path::{Path, PathBuf};
|
||||
use tree_sitter::{self, PropertyStateJSON, PropertyTransitionJSON};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Serialize)]
|
||||
#[serde(untagged)]
|
||||
enum PropertyValue {
|
||||
String(String),
|
||||
Object(PropertySet),
|
||||
Array(Vec<PropertyValue>),
|
||||
}
|
||||
|
||||
type PropertySet = BTreeMap<String, PropertyValue>;
|
||||
type PropertySheetJSON = tree_sitter::PropertySheetJSON<PropertySet>;
|
||||
type StateId = u32;
|
||||
type PropertySetId = u32;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
struct SelectorStep {
|
||||
kind: String,
|
||||
is_named: bool,
|
||||
is_immediate: bool,
|
||||
child_index: Option<i32>,
|
||||
text_pattern: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct Selector(Vec<SelectorStep>);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct Rule {
|
||||
selectors: Vec<Selector>,
|
||||
properties: PropertySet,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
struct PropertyItem {
|
||||
rule_id: u32,
|
||||
selector_id: u32,
|
||||
step_id: u32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct PropertyItemSet(BTreeSet<PropertyItem>);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct SelectorMatch {
|
||||
specificity: u32,
|
||||
rule_id: u32,
|
||||
selector_id: u32,
|
||||
}
|
||||
|
||||
struct Builder {
|
||||
rules: Vec<Rule>,
|
||||
output: PropertySheetJSON,
|
||||
ids_by_item_set: HashMap<PropertyItemSet, StateId>,
|
||||
ids_by_property_set: HashMap<PropertySet, PropertySetId>,
|
||||
item_set_queue: VecDeque<(PropertyItemSet, StateId)>,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
fn new(rules: Vec<Rule>) -> Self {
|
||||
Builder {
|
||||
rules,
|
||||
output: PropertySheetJSON {
|
||||
states: Vec::new(),
|
||||
property_sets: Vec::new(),
|
||||
},
|
||||
ids_by_item_set: HashMap::new(),
|
||||
ids_by_property_set: HashMap::new(),
|
||||
item_set_queue: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn build(self) -> PropertySheetJSON {
|
||||
let mut start_item_set = PropertyItemSet(BTreeSet::new());
|
||||
|
||||
self.output
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for PropertyItemSet {
|
||||
fn hash<H: Hasher>(&self, h: &mut H) {
|
||||
h.write_usize(self.0.len());
|
||||
for entry in &self.0 {
|
||||
entry.hash(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SelectorStep {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(")?;
|
||||
if self.is_named {
|
||||
write!(f, "{}", self.kind)?;
|
||||
} else {
|
||||
write!(f, "\"{}\"", self.kind)?;
|
||||
}
|
||||
if let Some(n) = self.child_index {
|
||||
write!(f, ":nth-child({})", n)?;
|
||||
}
|
||||
if let Some(t) = &self.text_pattern {
|
||||
write!(f, "[text='{}']", t)?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Selector {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "[")?;
|
||||
for (i, step) in self.0.iter().enumerate() {
|
||||
if step.is_immediate {
|
||||
write!(f, " > ")?;
|
||||
} else if i > 0 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
write!(f, "{:?}", step)?;
|
||||
}
|
||||
write!(f, "]")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_property_sheets(repo_path: &Path) -> Result<()> {
|
||||
let src_dir_path = repo_path.join("src");
|
||||
let properties_dir_path = repo_path.join("properties");
|
||||
|
||||
for entry in fs::read_dir(properties_dir_path)? {
|
||||
let property_sheet_css_path = entry?.path();
|
||||
let rules = parse_property_sheet(&property_sheet_css_path)?;
|
||||
|
||||
for rule in &rules {
|
||||
eprintln!("rule: {:?}", rule);
|
||||
}
|
||||
|
||||
let sheet = Builder::new(rules).build();
|
||||
let property_sheet_json_path = src_dir_path
|
||||
.join(property_sheet_css_path.file_name().unwrap())
|
||||
.with_extension("json");
|
||||
let mut property_sheet_json_file = File::create(property_sheet_json_path)?;
|
||||
serde_json::to_writer_pretty(&mut property_sheet_json_file, &sheet)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_property_sheet(path: &Path) -> Result<Vec<Rule>> {
|
||||
let mut i = 0;
|
||||
let mut items = rsass::parse_scss_file(path)?;
|
||||
while i < items.len() {
|
||||
match &items[i] {
|
||||
rsass::Item::Import(arg) => {
|
||||
if let Some(s) = get_sass_string(arg) {
|
||||
let import_path = resolve_path(path, s)?;
|
||||
let imported_items = rsass::parse_scss_file(&import_path)?;
|
||||
items.splice(i..(i + 1), imported_items);
|
||||
continue;
|
||||
} else {
|
||||
return Err(Error("@import arguments must be strings".to_string()));
|
||||
}
|
||||
}
|
||||
rsass::Item::AtRule { name, args, .. } => match name.as_str() {
|
||||
"schema" => {
|
||||
if let Some(s) = get_sass_string(args) {
|
||||
let schema_path = resolve_path(path, s)?;
|
||||
eprintln!("schema path: {:?}", schema_path);
|
||||
items.remove(i);
|
||||
continue;
|
||||
} else {
|
||||
return Err(Error("@schema arguments must be strings".to_string()));
|
||||
}
|
||||
}
|
||||
_ => return Err(Error(format!("Unsupported at-rule '{}'", name))),
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut result = Vec::new();
|
||||
let selector_prefixes = vec![Vec::new()];
|
||||
parse_sass_items(items, &selector_prefixes, &mut result)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn parse_sass_items(
|
||||
items: Vec<rsass::Item>,
|
||||
selector_prefixes: &Vec<Vec<SelectorStep>>,
|
||||
result: &mut Vec<Rule>,
|
||||
) -> Result<()> {
|
||||
let mut properties = PropertySet::new();
|
||||
for item in items {
|
||||
match item {
|
||||
rsass::Item::None | rsass::Item::Comment(_) => {}
|
||||
rsass::Item::Property(name, value) => {
|
||||
properties.insert(name.to_string(), parse_sass_value(&value)?);
|
||||
}
|
||||
rsass::Item::Rule(selectors, items) => {
|
||||
let mut full_selectors = Vec::new();
|
||||
for prefix in selector_prefixes {
|
||||
let mut part_string = String::new();
|
||||
let mut next_step_is_immediate = false;
|
||||
for selector in &selectors.s {
|
||||
let mut prefix = prefix.clone();
|
||||
for part in &selector.0 {
|
||||
part_string.clear();
|
||||
write!(&mut part_string, "{}", part).unwrap();
|
||||
let part_string = part_string.trim();
|
||||
if !part_string.is_empty() {
|
||||
if part_string == "&" {
|
||||
continue;
|
||||
} else if part_string.starts_with("[text=") {
|
||||
if let Some(last_step) = prefix.last_mut() {
|
||||
last_step.text_pattern = Some(
|
||||
part_string[7..(part_string.len() - 2)].to_string(),
|
||||
)
|
||||
}
|
||||
} else if part_string == ">" {
|
||||
next_step_is_immediate = true;
|
||||
} else if part_string.starts_with("[token=") {
|
||||
prefix.push(SelectorStep {
|
||||
kind: part_string[8..(part_string.len() - 2)].to_string(),
|
||||
is_named: false,
|
||||
child_index: None,
|
||||
text_pattern: None,
|
||||
is_immediate: next_step_is_immediate,
|
||||
});
|
||||
next_step_is_immediate = false;
|
||||
} else {
|
||||
prefix.push(SelectorStep {
|
||||
kind: part_string.to_string(),
|
||||
is_named: true,
|
||||
child_index: None,
|
||||
text_pattern: None,
|
||||
is_immediate: next_step_is_immediate,
|
||||
});
|
||||
next_step_is_immediate = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
full_selectors.push(prefix);
|
||||
}
|
||||
}
|
||||
parse_sass_items(items, &full_selectors, result)?;
|
||||
}
|
||||
_ => return Err(Error(format!("Unsupported syntax type {:?}", item))),
|
||||
}
|
||||
}
|
||||
|
||||
if !properties.is_empty() {
|
||||
result.push(Rule {
|
||||
selectors: selector_prefixes.iter().cloned().map(Selector).collect(),
|
||||
properties,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_sass_value(value: &Value) -> Result<PropertyValue> {
|
||||
match value {
|
||||
Value::Literal(s) => {
|
||||
if let Some(s) = s.single_raw() {
|
||||
Ok(PropertyValue::String(s.to_string()))
|
||||
} else {
|
||||
Err(Error("String interpolation is not supported".to_string()))
|
||||
}
|
||||
}
|
||||
Value::Call(name, raw_args) => {
|
||||
if let Some(name) = name.single_raw() {
|
||||
let mut args = Vec::new();
|
||||
for (_, arg) in raw_args.iter() {
|
||||
args.push(parse_sass_value(arg)?);
|
||||
}
|
||||
let mut result = PropertySet::new();
|
||||
result.insert("name".to_string(), PropertyValue::String(name.to_string()));
|
||||
result.insert("args".to_string(), PropertyValue::Array(args));
|
||||
Ok(PropertyValue::Object(result))
|
||||
} else {
|
||||
Err(Error("String interpolation is not supported".to_string()))
|
||||
}
|
||||
}
|
||||
Value::List(elements, ..) => {
|
||||
let mut result = Vec::new();
|
||||
for element in elements {
|
||||
result.push(parse_sass_value(element)?);
|
||||
}
|
||||
Ok(PropertyValue::Array(result))
|
||||
}
|
||||
Value::True => Ok(PropertyValue::String("true".to_string())),
|
||||
Value::False => Ok(PropertyValue::String("false".to_string())),
|
||||
_ => Err(Error(
|
||||
"Property values must be strings or function calls".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_sass_string(value: &Value) -> Option<&str> {
|
||||
if let Value::Literal(s) = value {
|
||||
s.single_raw()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_path(base: &Path, path: impl AsRef<Path>) -> Result<PathBuf> {
|
||||
let mut result = base.to_owned();
|
||||
result.pop();
|
||||
result.push(path.as_ref());
|
||||
if result.exists() {
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(Error(format!(
|
||||
"Could not resolve import path {:?}",
|
||||
path.as_ref()
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ extern crate log;
|
|||
extern crate serde_derive;
|
||||
extern crate hashbrown;
|
||||
extern crate regex;
|
||||
extern crate rsass;
|
||||
extern crate serde_json;
|
||||
|
||||
mod error;
|
||||
|
|
@ -39,6 +40,7 @@ fn run() -> error::Result<()> {
|
|||
SubCommand::with_name("generate")
|
||||
.about("Generate a parser")
|
||||
.arg(Arg::with_name("log").long("log"))
|
||||
.arg(Arg::with_name("properties-only").long("properties"))
|
||||
.arg(
|
||||
Arg::with_name("state-ids-to-log")
|
||||
.long("log-state")
|
||||
|
|
@ -77,13 +79,14 @@ fn run() -> error::Result<()> {
|
|||
}
|
||||
|
||||
let minimize = !matches.is_present("no-minimize");
|
||||
let properties_only = matches.is_present("properties-only");
|
||||
let state_ids_to_log = matches
|
||||
.values_of("state-ids-to-log")
|
||||
.map_or(Vec::new(), |ids| {
|
||||
ids.filter_map(|id| usize::from_str_radix(id, 10).ok())
|
||||
.collect()
|
||||
});
|
||||
generate::generate_parser_for_grammar(¤t_dir, minimize, state_ids_to_log)?;
|
||||
generate::generate_parser_for_grammar(¤t_dir, minimize, state_ids_to_log, properties_only)?;
|
||||
} else if let Some(matches) = matches.subcommand_matches("test") {
|
||||
let debug = matches.is_present("debug");
|
||||
let debug_graph = matches.is_present("debug-graph");
|
||||
|
|
|
|||
|
|
@ -80,6 +80,29 @@ pub struct PropertySheet<P = HashMap<String, String>> {
|
|||
text_regexes: Vec<Regex>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct PropertyTransitionJSON {
|
||||
#[serde(rename = "type")]
|
||||
pub kind: String,
|
||||
pub named: bool,
|
||||
pub index: Option<usize>,
|
||||
pub text: Option<String>,
|
||||
pub state_id: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct PropertyStateJSON {
|
||||
pub transitions: Vec<PropertyTransitionJSON>,
|
||||
pub property_set_id: usize,
|
||||
pub default_next_state_id: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct PropertySheetJSON<P> {
|
||||
pub states: Vec<PropertyStateJSON>,
|
||||
pub property_sets: Vec<P>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Node<'a>(ffi::TSNode, PhantomData<&'a ()>);
|
||||
|
||||
|
|
@ -189,7 +212,7 @@ impl Parser {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn print_dot_graphs(&mut self, file: & impl AsRawFd) {
|
||||
pub fn print_dot_graphs(&mut self, file: &impl AsRawFd) {
|
||||
let fd = file.as_raw_fd();
|
||||
unsafe { ffi::ts_parser_print_dot_graphs(self.0, ffi::dup(fd)) }
|
||||
}
|
||||
|
|
@ -754,29 +777,6 @@ impl<P> PropertySheet<P> {
|
|||
where
|
||||
P: DeserializeOwned,
|
||||
{
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct PropertyTransitionJSON {
|
||||
#[serde(rename = "type")]
|
||||
kind: String,
|
||||
named: bool,
|
||||
index: Option<usize>,
|
||||
text: Option<String>,
|
||||
state_id: usize,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct PropertyStateJSON {
|
||||
transitions: Vec<PropertyTransitionJSON>,
|
||||
property_set_id: usize,
|
||||
default_next_state_id: usize,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct PropertySheetJSON<P> {
|
||||
states: Vec<PropertyStateJSON>,
|
||||
property_sets: Vec<P>,
|
||||
}
|
||||
|
||||
let input: PropertySheetJSON<P> =
|
||||
serde_json::from_str(json).map_err(PropertySheetError::InvalidJSON)?;
|
||||
let mut states = Vec::new();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue