From d7690b6ae6a5fe780db9c821562e41065d9d51e9 Mon Sep 17 00:00:00 2001 From: Yoav Lavi Date: Tue, 22 Feb 2022 18:31:20 +0100 Subject: [PATCH] add option keyword --- Cargo.lock | 6 ++--- README.md | 3 ++- crates/melody_cli/Cargo.toml | 4 +-- crates/melody_compiler/Cargo.toml | 2 +- crates/melody_compiler/src/lib.rs | 25 ++++++++++++++++++ crates/melody_wasm/Cargo.toml | 4 +-- docs/docs/syntax.md | 1 + extensions/vscode/package.json | 2 +- .../vscode/syntaxes/melody.tmLanguage.json | 4 +-- playground/package.json | 2 +- playground/src/main.ts | 4 +-- playground/src/wasm/melody_wasm_bg.wasm | Bin 140099 -> 140309 bytes 12 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aecefbd2..bb38d2a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,7 +168,7 @@ dependencies = [ [[package]] name = "melody_cli" -version = "0.1.1" +version = "0.2.0" dependencies = [ "clap", "colored", @@ -177,14 +177,14 @@ dependencies = [ [[package]] name = "melody_compiler" -version = "0.1.1" +version = "0.2.0" dependencies = [ "logos", ] [[package]] name = "melody_wasm" -version = "0.1.1" +version = "0.2.0" dependencies = [ "melody_compiler", "wasm-bindgen", diff --git a/README.md b/README.md index 592479ad..3585c545 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ OPTIONS: - `char` - matches a single character, equivalent to regex `.` - `some` - used with `of` to express 1 or more of a pattern, equivalent to regex `+` - `over` - used with `of` to express more than an amount of a pattern, equivalent to regex `{6,}` (assuming `over 5 of ...`) +- `option` - used with `of` to express 0 or 1 of a pattern, equivalent to regex `?` ## Symbols @@ -211,6 +212,7 @@ The Melody file extension is `.mdy` | `over 5 of "A";` | `A{6,}` | ✅ | | WASM binding | | ✅ | | Rust crate | | ✅ | +| `option of` | `?` | ✅ | | enforce group close | | 🐣 | | tests | | 🐣 | | `not ;` | `\S` | ❌ | @@ -227,7 +229,6 @@ The Melody file extension is `.mdy` | `not "A";` | `[^A]` | ❔ | | `flags: global, multiline, ...` | `/.../gm...` | ❔ | | `/* comment */` | | ❔ | -| `maybe of` | `?` | ❔ | | `maybe some of` | `*` | ❔ | | `either of ..., ...` | `\|` | ❔ | | `any of "a", "b", "c"` | `[abc]` | ❔ | diff --git a/crates/melody_cli/Cargo.toml b/crates/melody_cli/Cargo.toml index 8f867301..abef7ac0 100644 --- a/crates/melody_cli/Cargo.toml +++ b/crates/melody_cli/Cargo.toml @@ -4,7 +4,7 @@ description = "A CLI wrapping the Melody language compiler" homepage = "https://github.com/yoav-lavi/melody" repository = "https://github.com/yoav-lavi/melody" readme = "README.md" -version = "0.1.1" +version = "0.2.0" edition = "2021" rust-version = "1.58.0" license = "MIT" @@ -13,7 +13,7 @@ keywords = ["melody", "melodylang"] [dependencies] clap = { version = "3.0.7", features = ["derive"] } colored = "2.0.0" -melody_compiler = { version = "0.1.1", path = "../melody_compiler" } +melody_compiler = { version = "0.2.0", path = "../melody_compiler" } [[bin]] name = "melody" diff --git a/crates/melody_compiler/Cargo.toml b/crates/melody_compiler/Cargo.toml index 578ef336..ee015775 100644 --- a/crates/melody_compiler/Cargo.toml +++ b/crates/melody_compiler/Cargo.toml @@ -4,7 +4,7 @@ description = "The Melody language compiler" homepage = "https://github.com/yoav-lavi/melody" repository = "https://github.com/yoav-lavi/melody" readme = "README.md" -version = "0.1.1" +version = "0.2.0" edition = "2021" rust-version = "1.58.0" license = "MIT" diff --git a/crates/melody_compiler/src/lib.rs b/crates/melody_compiler/src/lib.rs index ea2418dd..11c85c62 100644 --- a/crates/melody_compiler/src/lib.rs +++ b/crates/melody_compiler/src/lib.rs @@ -14,6 +14,9 @@ enum Token { #[regex("some of")] SomeExpression, + #[regex("option of")] + OptionExpression, + #[regex(r#""(\\"|[^"\n])*""#, raw)] RawDouble(String), @@ -270,6 +273,10 @@ pub fn compiler(source: &str) -> Result { quantifier = Some(String::from("+")); None } + Token::OptionExpression => { + quantifier = Some(String::from("?")); + None + } // direct replacements Token::LineStart => handle_quantifier(String::from("^"), quantifier.clone(), false), @@ -495,3 +502,21 @@ fn some_test() { .unwrap(); assert_eq!(multiple_output, "/(?:ABC)+/"); } + +#[test] +fn option_test() { + let single_output = compiler( + r#" + option of char; + "#, + ) + .unwrap(); + assert_eq!(single_output, "/.?/"); + let multiple_output = compiler( + r#" + option of "ABC"; + "#, + ) + .unwrap(); + assert_eq!(multiple_output, "/(?:ABC)?/"); +} diff --git a/crates/melody_wasm/Cargo.toml b/crates/melody_wasm/Cargo.toml index 7da22646..faea5e11 100644 --- a/crates/melody_wasm/Cargo.toml +++ b/crates/melody_wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "melody_wasm" -version = "0.1.1" +version = "0.2.0" edition = "2021" rust-version = "1.58.0" description = "WASM bindings for the Melody language compiler" @@ -13,4 +13,4 @@ crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2" -melody_compiler = { version = "0.1.1", path = "../melody_compiler" } +melody_compiler = { version = "0.2.0", path = "../melody_compiler" } diff --git a/docs/docs/syntax.md b/docs/docs/syntax.md index b755ef42..07a17ed1 100644 --- a/docs/docs/syntax.md +++ b/docs/docs/syntax.md @@ -15,6 +15,7 @@ sidebar_position: 6 - `char` - matches a single character, equivalent to regex `.` - `some` - used with `of` to express 1 or more of a pattern, equivalent to regex `+` - `over` - used with `of` to express more than an amount of a pattern, equivalent to regex `{6,}` (assuming `over 5 of ...`) +- `option` - used with `of` to express 0 or 1 of a pattern, equivalent to regex `?` ## Symbols diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index 4f17533a..3d3f7299 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -2,7 +2,7 @@ "name": "melody", "displayName": "Melody", "description": "Melody syntax highlighting", - "version": "0.0.3", + "version": "0.2.0", "publisher": "yoavlavi", "repository": { "type": "git", diff --git a/extensions/vscode/syntaxes/melody.tmLanguage.json b/extensions/vscode/syntaxes/melody.tmLanguage.json index 414d0807..aa7920c2 100644 --- a/extensions/vscode/syntaxes/melody.tmLanguage.json +++ b/extensions/vscode/syntaxes/melody.tmLanguage.json @@ -23,7 +23,7 @@ "patterns": [ { "name": "keyword.other.melody", - "match": "\\b(of|capture|to|of|some|match|over)\\b" + "match": "\\b(of|capture|to|of|some|match|over|option)\\b" } ] }, @@ -35,7 +35,7 @@ }, { "name": "constant.character.melody", - "match": "\\b(A|Z|a|z)\\b" + "match": "\\b[A-Za-z]\\b" }, { "name": "constant.character.melody", diff --git a/playground/package.json b/playground/package.json index 601e8cd9..d680850d 100644 --- a/playground/package.json +++ b/playground/package.json @@ -1,7 +1,7 @@ { "name": "playground", "private": true, - "version": "0.0.0", + "version": "0.2.0", "scripts": { "dev": "vite", "build": "tsc && vite build", diff --git a/playground/src/main.ts b/playground/src/main.ts index c16d1e70..8333bb4c 100644 --- a/playground/src/main.ts +++ b/playground/src/main.ts @@ -38,7 +38,7 @@ languages.register({ id: MELODY_LANGUAGE_ID }); languages.setMonarchTokensProvider(MELODY_LANGUAGE_ID, { tokenizer: { root: [ - [/(of|capture|to|of|some|match|over)/, 'keyword'], + [/(of|capture|to|of|some|match|over|option)/, 'keyword'], [/\d/, 'digit'], [/"(\\"|[^"\n])*"/, 'string'], [/'(\\'|[^'\n])*'/, 'string'], @@ -47,7 +47,7 @@ languages.setMonarchTokensProvider(MELODY_LANGUAGE_ID, { 'character', ], [/(start|end|char)/, 'character'], - [/(A|Z|a|z)/, 'character'], + [/[A-Za-z]/, 'character'], [/\/\/.*/, 'comment'], ], }, diff --git a/playground/src/wasm/melody_wasm_bg.wasm b/playground/src/wasm/melody_wasm_bg.wasm index 6bdadba8af95a1fecde00ee854adb9656a862585..b61e2c93590fe5f3544c6846b4457832427bff99 100644 GIT binary patch delta 15511 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 I>syTf0$kqNi2wiq