From b814c57355a414294e85c1967d6724f076365fdb Mon Sep 17 00:00:00 2001 From: ef3d0c3e Date: Tue, 30 Jul 2024 11:01:22 +0200 Subject: [PATCH] Added bindings --- src/elements/code.rs | 5 +- src/elements/comment.rs | 2 +- src/elements/graphviz.rs | 2 +- src/elements/import.rs | 2 +- src/elements/link.rs | 2 +- src/elements/list.rs | 2 +- src/elements/media.rs | 6 +- src/elements/paragraph.rs | 2 +- src/elements/raw.rs | 4 +- src/elements/reference.rs | 6 +- src/elements/script.rs | 2 +- src/elements/section.rs | 4 +- src/elements/style.rs | 2 +- src/elements/tex.rs | 2 +- src/elements/text.rs | 4 +- src/elements/variable.rs | 564 ++++++++++++++++++++++---------------- src/lua/kernel.rs | 17 +- src/parser/rule.rs | 6 +- 18 files changed, 370 insertions(+), 264 deletions(-) diff --git a/src/elements/code.rs b/src/elements/code.rs index 132e91f..0ebb050 100644 --- a/src/elements/code.rs +++ b/src/elements/code.rs @@ -544,8 +544,7 @@ impl RegexRule for CodeRule { reports } - // TODO - fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { + fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option)>> { let mut bindings = vec![]; bindings.push(( "push_inline".to_string(), @@ -647,7 +646,7 @@ impl RegexRule for CodeRule { .unwrap(), )); - bindings + Some(bindings) } } diff --git a/src/elements/comment.rs b/src/elements/comment.rs index a75e21d..3a59862 100644 --- a/src/elements/comment.rs +++ b/src/elements/comment.rs @@ -80,5 +80,5 @@ impl RegexRule for CommentRule { return reports; } - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/elements/graphviz.rs b/src/elements/graphviz.rs index 0dfaafe..29d7f58 100644 --- a/src/elements/graphviz.rs +++ b/src/elements/graphviz.rs @@ -371,5 +371,5 @@ impl RegexRule for GraphRule { } // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/elements/import.rs b/src/elements/import.rs index 919ec43..07c4222 100644 --- a/src/elements/import.rs +++ b/src/elements/import.rs @@ -178,5 +178,5 @@ impl RegexRule for ImportRule { return result; } - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/elements/link.rs b/src/elements/link.rs index 6869c63..691e7bd 100644 --- a/src/elements/link.rs +++ b/src/elements/link.rs @@ -171,5 +171,5 @@ impl RegexRule for LinkRule { } // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/elements/list.rs b/src/elements/list.rs index e6e093f..8a6397d 100644 --- a/src/elements/list.rs +++ b/src/elements/list.rs @@ -337,5 +337,5 @@ impl Rule for ListRule } // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/elements/media.rs b/src/elements/media.rs index 3499d65..f7e4b23 100644 --- a/src/elements/media.rs +++ b/src/elements/media.rs @@ -7,6 +7,8 @@ use ariadne::Fmt; use ariadne::Label; use ariadne::Report; use ariadne::ReportKind; +use mlua::Function; +use mlua::Lua; use regex::Captures; use regex::Match; use regex::Regex; @@ -518,9 +520,7 @@ impl RegexRule for MediaRule { reports } - fn lua_bindings<'lua>(&self, _lua: &'lua mlua::Lua) -> Vec<(String, mlua::Function<'lua>)> { - vec![] - } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } #[cfg(test)] diff --git a/src/elements/paragraph.rs b/src/elements/paragraph.rs index 3d954a0..3285f2f 100644 --- a/src/elements/paragraph.rs +++ b/src/elements/paragraph.rs @@ -150,5 +150,5 @@ impl Rule for ParagraphRule { } // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/elements/raw.rs b/src/elements/raw.rs index 34d0760..2af1c11 100644 --- a/src/elements/raw.rs +++ b/src/elements/raw.rs @@ -231,7 +231,7 @@ impl RegexRule for RawRule { reports } - fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { + fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option)>> { let mut bindings = vec![]; bindings.push(( @@ -270,7 +270,7 @@ impl RegexRule for RawRule { .unwrap(), )); - bindings + Some(bindings) } } diff --git a/src/elements/reference.rs b/src/elements/reference.rs index 3d4afe1..e467fc9 100644 --- a/src/elements/reference.rs +++ b/src/elements/reference.rs @@ -6,6 +6,8 @@ use ariadne::Fmt; use ariadne::Label; use ariadne::Report; use ariadne::ReportKind; +use mlua::Function; +use mlua::Lua; use regex::Captures; use regex::Match; use regex::Regex; @@ -205,7 +207,5 @@ impl RegexRule for ReferenceRule { reports } - fn lua_bindings<'lua>(&self, _lua: &'lua mlua::Lua) -> Vec<(String, mlua::Function<'lua>)> { - vec![] - } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/elements/script.rs b/src/elements/script.rs index eec6359..dab19da 100644 --- a/src/elements/script.rs +++ b/src/elements/script.rs @@ -275,5 +275,5 @@ impl RegexRule for ScriptRule { } // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/elements/section.rs b/src/elements/section.rs index a319866..1e85e5a 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -235,7 +235,7 @@ impl RegexRule for SectionRule { return result; } - fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { + fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option)>> { let mut bindings = vec![]; bindings.push(( @@ -280,6 +280,6 @@ impl RegexRule for SectionRule { .unwrap(), )); - bindings + Some(bindings) } } diff --git a/src/elements/style.rs b/src/elements/style.rs index a3248b1..2657403 100644 --- a/src/elements/style.rs +++ b/src/elements/style.rs @@ -183,5 +183,5 @@ impl RegexRule for StyleRule } // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/elements/tex.rs b/src/elements/tex.rs index b8af559..b1e80e5 100644 --- a/src/elements/tex.rs +++ b/src/elements/tex.rs @@ -430,7 +430,7 @@ impl RegexRule for TexRule { } // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } #[cfg(test)] diff --git a/src/elements/text.rs b/src/elements/text.rs index cf0a2ac..54a4ccd 100644 --- a/src/elements/text.rs +++ b/src/elements/text.rs @@ -61,7 +61,7 @@ impl Rule for TextRule { panic!("Text cannot match"); } - fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { + fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option)>> { let mut bindings = vec![]; bindings.push(( "push".to_string(), @@ -83,6 +83,6 @@ impl Rule for TextRule { .unwrap(), )); - bindings + Some(bindings) } } diff --git a/src/elements/variable.rs b/src/elements/variable.rs index bd8488d..dd21a31 100644 --- a/src/elements/variable.rs +++ b/src/elements/variable.rs @@ -1,78 +1,109 @@ -use mlua::{Function, Lua}; +use crate::document::document::Document; +use crate::document::variable::BaseVariable; +use crate::document::variable::PathVariable; +use crate::document::variable::Variable; +use crate::lua::kernel::CTX; +use crate::parser::parser::Parser; +use crate::parser::parser::ReportColors; +use crate::parser::rule::RegexRule; +use crate::parser::source::Source; +use crate::parser::source::Token; +use ariadne::Fmt; +use ariadne::Label; +use ariadne::Report; +use ariadne::ReportKind; +use mlua::Function; +use mlua::Lua; use regex::Regex; -use crate::{document::document::Document, parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, Token}}}; -use ariadne::{Report, Fmt, Label, ReportKind}; -use crate::document::variable::{BaseVariable, PathVariable, Variable}; -use std::{ops::Range, rc::Rc}; +use std::ops::Range; +use std::rc::Rc; +use std::str::FromStr; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum VariableKind { + Regular, + Path, +} + +impl FromStr for VariableKind { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "regular" | "" => Ok(VariableKind::Regular), + "path" | "'" => Ok(VariableKind::Path), + _ => Err(format!("Uknnown variable kind: `{s}`")), + } + } +} pub struct VariableRule { re: [Regex; 1], - kinds: Vec<(String, String)>, + kinds: Vec<(String, String)>, } impl VariableRule { pub fn new() -> Self { Self { - re: [Regex::new(r"(?:^|\n)@([^[:alpha:]])?(.*?)=((?:\\\n|.)*)").unwrap()], - kinds: vec![ - ("".into(), "Regular".into()), - ("'".into(), "Path".into()) - ] - } + re: [Regex::new(r"(?:^|\n)@([^[:alpha:]])?(.*?)=((?:\\\n|.)*)").unwrap()], + kinds: vec![("".into(), "Regular".into()), ("'".into(), "Path".into())], + } } - pub fn make_variable(&self, colors: &ReportColors, location: Token, kind: usize, name: String, value: String) -> Result, String> - { - match self.kinds[kind].0.as_str() - { - "" => { - Ok(Rc::new(BaseVariable::new(location, name, value))) - } - "'" => { - match std::fs::canonicalize(value.as_str()) // TODO: not canonicalize + pub fn make_variable( + &self, + colors: &ReportColors, + location: Token, + kind: usize, + name: String, + value: String, + ) -> Result, String> { + match self.kinds[kind].0.as_str() { + "" => Ok(Rc::new(BaseVariable::new(location, name, value))), + "'" => { + match std::fs::canonicalize(value.as_str()) // TODO: not canonicalize { Ok(path) => Ok(Rc::new(PathVariable::new(location, name, path))), Err(e) => Err(format!("Unable to canonicalize path `{}`: {}", value.fg(colors.highlight), e.to_string())) } - } - _ => panic!("Unhandled variable kind") - } - } + } + _ => panic!("Unhandled variable kind"), + } + } - // Trim and check variable name for validity - pub fn validate_name<'a>(colors: &ReportColors, original_name: &'a str) -> Result<&'a str, String> - { - let name = original_name.trim_start().trim_end(); - if name.contains("%") - { - return Err(format!("Name cannot contain '{}'", - "%".fg(colors.info))); - } - return Ok(name); - } + // Trim and check variable name for validity + pub fn validate_name<'a>( + colors: &ReportColors, + original_name: &'a str, + ) -> Result<&'a str, String> { + let name = original_name.trim_start().trim_end(); + if name.contains("%") { + return Err(format!("Name cannot contain '{}'", "%".fg(colors.info))); + } + return Ok(name); + } - pub fn validate_value(_colors: &ReportColors, original_value: &str) -> Result - { + pub fn validate_value(_colors: &ReportColors, original_value: &str) -> Result { let mut escaped = 0usize; let mut result = String::new(); for c in original_value.trim_start().trim_end().chars() { - if c == '\\' { escaped += 1 } - else if c == '\n' { + if c == '\\' { + escaped += 1 + } else if c == '\n' { match escaped { 0 => return Err("Unknown error wile capturing variable".to_string()), // Remove '\n' - 1 => {}, + 1 => {} // Insert '\n' _ => { result.push(c); - (0..escaped-2).for_each(|_| result.push('\\')); + (0..escaped - 2).for_each(|_| result.push('\\')); } } escaped = 0; - } - else { + } else { (0..escaped).for_each(|_| result.push('\\')); escaped = 0; result.push(c); @@ -81,7 +112,7 @@ impl VariableRule { (0..escaped).for_each(|_| result.push('\\')); Ok(result) - } + } } impl RegexRule for VariableRule { @@ -89,233 +120,306 @@ impl RegexRule for VariableRule { fn regexes(&self) -> &[Regex] { &self.re } - fn on_regex_match<'a>(&self, _: usize, parser: &dyn Parser, document: &'a dyn Document, token: Token, matches: regex::Captures) -> Vec, Range)>> - { + fn on_regex_match<'a>( + &self, + _: usize, + parser: &dyn Parser, + document: &'a dyn Document, + token: Token, + matches: regex::Captures, + ) -> Vec, Range)>> { let mut result = vec![]; - // [Optional] variable kind - let var_kind = match matches.get(1) - { + // [Optional] variable kind + let var_kind = match matches.get(1) { Some(kind) => { - // Find kind - let r = self.kinds.iter().enumerate().find(|(_i, (ref char, ref _name))| { - char == kind.as_str() }); + // Find kind + let r = self + .kinds + .iter() + .enumerate() + .find(|(_i, (ref char, ref _name))| char == kind.as_str()); - // Unknown kind specified - if r.is_none() - { - result.push( - Report::build(ReportKind::Error, token.source(), kind.start()) - .with_message("Unknown variable kind") - .with_label( - Label::new((token.source(), kind.range())) - .with_message(format!("Variable kind `{}` is unknown", - kind.as_str().fg(parser.colors().highlight))) - .with_color(parser.colors().error)) - .with_help(format!("Leave empty for regular variables. Available variable kinds:{}", - self.kinds.iter().skip(1).fold("".to_string(), |acc, (char, name)| { - acc + format!("\n - `{}` : {}", - char.fg(parser.colors().highlight), - name.fg(parser.colors().info)).as_str() - }))) - .finish()); + // Unknown kind specified + if r.is_none() { + result.push( + Report::build(ReportKind::Error, token.source(), kind.start()) + .with_message("Unknown variable kind") + .with_label( + Label::new((token.source(), kind.range())) + .with_message(format!( + "Variable kind `{}` is unknown", + kind.as_str().fg(parser.colors().highlight) + )) + .with_color(parser.colors().error), + ) + .with_help(format!( + "Leave empty for regular variables. Available variable kinds:{}", + self.kinds.iter().skip(1).fold( + "".to_string(), + |acc, (char, name)| { + acc + format!( + "\n - `{}` : {}", + char.fg(parser.colors().highlight), + name.fg(parser.colors().info) + ) + .as_str() + } + ) + )) + .finish(), + ); - return result; - } + return result; + } - r.unwrap().0 + r.unwrap().0 } None => 0, }; - let var_name = match matches.get(2) - { - Some(name) => { - match VariableRule::validate_name(&parser.colors(), name.as_str()) - { - Ok(var_name) => var_name, - Err(msg) => { - result.push( - Report::build(ReportKind::Error, token.source(), name.start()) - .with_message("Invalid variable name") - .with_label( - Label::new((token.source(), name.range())) - .with_message(format!("Variable name `{}` is not allowed. {msg}", - name.as_str().fg(parser.colors().highlight))) - .with_color(parser.colors().error)) - .finish()); + let var_name = match matches.get(2) { + Some(name) => match VariableRule::validate_name(&parser.colors(), name.as_str()) { + Ok(var_name) => var_name, + Err(msg) => { + result.push( + Report::build(ReportKind::Error, token.source(), name.start()) + .with_message("Invalid variable name") + .with_label( + Label::new((token.source(), name.range())) + .with_message(format!( + "Variable name `{}` is not allowed. {msg}", + name.as_str().fg(parser.colors().highlight) + )) + .with_color(parser.colors().error), + ) + .finish(), + ); - return result; - }, - } - }, - _ => panic!("Unknown variable name") - }; + return result; + } + }, + _ => panic!("Unknown variable name"), + }; - let var_value = match matches.get(3) - { - Some(value) => { - match VariableRule::validate_value(&parser.colors(), value.as_str()) - { - Ok(var_value) => var_value, - Err(msg ) => { - result.push( - Report::build(ReportKind::Error, token.source(), value.start()) - .with_message("Invalid variable value") - .with_label( - Label::new((token.source(), value.range())) - .with_message(format!("Variable value `{}` is not allowed. {msg}", - value.as_str().fg(parser.colors().highlight))) - .with_color(parser.colors().error)) - .finish()); + let var_value = match matches.get(3) { + Some(value) => match VariableRule::validate_value(&parser.colors(), value.as_str()) { + Ok(var_value) => var_value, + Err(msg) => { + result.push( + Report::build(ReportKind::Error, token.source(), value.start()) + .with_message("Invalid variable value") + .with_label( + Label::new((token.source(), value.range())) + .with_message(format!( + "Variable value `{}` is not allowed. {msg}", + value.as_str().fg(parser.colors().highlight) + )) + .with_color(parser.colors().error), + ) + .finish(), + ); - return result; - } - } - } - _ => panic!("Invalid variable value") - }; + return result; + } + }, + _ => panic!("Invalid variable value"), + }; - match self.make_variable(&parser.colors(), token.clone(), var_kind, var_name.to_string(), var_value) - { - Ok(variable) => document.add_variable(variable), - Err(msg) => { - let m = matches.get(0).unwrap(); - result.push( - Report::build(ReportKind::Error, token.source(), m.start()) - .with_message("Unable to create variable") - .with_label( - Label::new((token.source(), m.start()+1 .. m.end() )) - .with_message(format!("Unable to create variable `{}`. {}", - var_name.fg(parser.colors().highlight), - msg)) - .with_color(parser.colors().error)) - .finish()); + match self.make_variable( + &parser.colors(), + token.clone(), + var_kind, + var_name.to_string(), + var_value, + ) { + Ok(variable) => document.add_variable(variable), + Err(msg) => { + let m = matches.get(0).unwrap(); + result.push( + Report::build(ReportKind::Error, token.source(), m.start()) + .with_message("Unable to create variable") + .with_label( + Label::new((token.source(), m.start() + 1..m.end())) + .with_message(format!( + "Unable to create variable `{}`. {}", + var_name.fg(parser.colors().highlight), + msg + )) + .with_color(parser.colors().error), + ) + .finish(), + ); - return result; - } - } + return result; + } + } - return result; + return result; } - // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option)>> { + let mut bindings = vec![]; + bindings.push(( + "insert".to_string(), + lua.create_function(|_, (name, value): (String, String)| { + CTX.with_borrow(|ctx| { + ctx.as_ref().map(|ctx| { + let var = Rc::new(BaseVariable::new(ctx.location.clone(), name, value)); + ctx.document.add_variable(var); + }) + }); + + Ok(()) + }) + .unwrap(), + )); + bindings.push(( + "get".to_string(), + lua.create_function(|_, name: String| { + let mut value: Option = None; + CTX.with_borrow(|ctx| { + ctx.as_ref().map(|ctx| { + if let Some(var) = ctx.document.get_variable(name.as_str()) + { + value = Some(var.to_string()); + } + }) + }); + + Ok(value) + }) + .unwrap(), + )); + + Some(bindings) + } } -pub struct VariableSubstitutionRule -{ +pub struct VariableSubstitutionRule { re: [Regex; 1], } impl VariableSubstitutionRule { pub fn new() -> Self { Self { - re: [Regex::new(r"%(.*?)%").unwrap()], - } + re: [Regex::new(r"%(.*?)%").unwrap()], + } } } -impl RegexRule for VariableSubstitutionRule -{ - fn name(&self) -> &'static str { "Variable Substitution" } +impl RegexRule for VariableSubstitutionRule { + fn name(&self) -> &'static str { "Variable Substitution" } - fn regexes(&self) -> &[regex::Regex] { &self.re } + fn regexes(&self) -> &[regex::Regex] { &self.re } - fn on_regex_match<'a>(&self, _index: usize, parser: &dyn Parser, document: &'a dyn Document<'a>, token: Token, matches: regex::Captures) -> Vec, Range)>> { + fn on_regex_match<'a>( + &self, + _index: usize, + parser: &dyn Parser, + document: &'a dyn Document<'a>, + token: Token, + matches: regex::Captures, + ) -> Vec, Range)>> { let mut result = vec![]; - let variable = match matches.get(1) - { - Some(name) => { - // Empty name - if name.as_str().is_empty() - { - result.push( - Report::build(ReportKind::Error, token.source(), name.start()) - .with_message("Empty variable name") - .with_label( - Label::new((token.source(), matches.get(0).unwrap().range())) - .with_message(format!("Missing variable name for substitution")) - .with_color(parser.colors().error)) - .finish()); + let variable = match matches.get(1) { + Some(name) => { + // Empty name + if name.as_str().is_empty() { + result.push( + Report::build(ReportKind::Error, token.source(), name.start()) + .with_message("Empty variable name") + .with_label( + Label::new((token.source(), matches.get(0).unwrap().range())) + .with_message(format!("Missing variable name for substitution")) + .with_color(parser.colors().error), + ) + .finish(), + ); - return result; - } - // Leading spaces - else if name.as_str().trim_start() != name.as_str() - { - result.push( - Report::build(ReportKind::Error, token.source(), name.start()) - .with_message("Invalid variable name") - .with_label( - Label::new((token.source(), name.range())) - .with_message(format!("Variable names contains leading spaces")) - .with_color(parser.colors().error)) - .with_help("Remove leading spaces") - .finish()); - - return result; - } - // Trailing spaces - else if name.as_str().trim_end() != name.as_str() - { - result.push( - Report::build(ReportKind::Error, token.source(), name.start()) - .with_message("Invalid variable name") - .with_label( - Label::new((token.source(), name.range())) - .with_message(format!("Variable names contains trailing spaces")) - .with_color(parser.colors().error)) - .with_help("Remove trailing spaces") - .finish()); - - return result; - } - // Invalid name - match VariableRule::validate_name(&parser.colors(), name.as_str()) - { - Err(msg) => - { - result.push( - Report::build(ReportKind::Error, token.source(), name.start()) + return result; + } + // Leading spaces + else if name.as_str().trim_start() != name.as_str() { + result.push( + Report::build(ReportKind::Error, token.source(), name.start()) .with_message("Invalid variable name") .with_label( Label::new((token.source(), name.range())) - .with_message(msg) - .with_color(parser.colors().error)) - .finish()); + .with_message(format!("Variable names contains leading spaces")) + .with_color(parser.colors().error), + ) + .with_help("Remove leading spaces") + .finish(), + ); + + return result; + } + // Trailing spaces + else if name.as_str().trim_end() != name.as_str() { + result.push( + Report::build(ReportKind::Error, token.source(), name.start()) + .with_message("Invalid variable name") + .with_label( + Label::new((token.source(), name.range())) + .with_message(format!( + "Variable names contains trailing spaces" + )) + .with_color(parser.colors().error), + ) + .with_help("Remove trailing spaces") + .finish(), + ); + + return result; + } + // Invalid name + match VariableRule::validate_name(&parser.colors(), name.as_str()) { + Err(msg) => { + result.push( + Report::build(ReportKind::Error, token.source(), name.start()) + .with_message("Invalid variable name") + .with_label( + Label::new((token.source(), name.range())) + .with_message(msg) + .with_color(parser.colors().error), + ) + .finish(), + ); return result; } - _ => {}, - } - + _ => {} + } + // Get variable - match document.get_variable(name.as_str()) - { - None => { - result.push( - Report::build(ReportKind::Error, token.source(), name.start()) - .with_message("Unknown variable name") - .with_label( - Label::new((token.source(), name.range())) - .with_message(format!("Unable to find variable with name: `{}`", - name.as_str().fg(parser.colors().highlight))) - .with_color(parser.colors().error)) - .finish()); - return result; - } - Some(var) => var, - } - }, - _ => panic!("Unknown error") - }; + match document.get_variable(name.as_str()) { + None => { + result.push( + Report::build(ReportKind::Error, token.source(), name.start()) + .with_message("Unknown variable name") + .with_label( + Label::new((token.source(), name.range())) + .with_message(format!( + "Unable to find variable with name: `{}`", + name.as_str().fg(parser.colors().highlight) + )) + .with_color(parser.colors().error), + ) + .finish(), + ); + return result; + } + Some(var) => var, + } + } + _ => panic!("Unknown error"), + }; variable.parse(token, parser, document); - return result; - } + return result; + } - // TODO - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] } + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>> { None } } diff --git a/src/lua/kernel.rs b/src/lua/kernel.rs index 8e0bb81..470b3db 100644 --- a/src/lua/kernel.rs +++ b/src/lua/kernel.rs @@ -34,15 +34,18 @@ impl Kernel { for rule in parser.rules() { - let table = lua.create_table().unwrap(); - let name = rule.name().to_lowercase(); - - for (fun_name, fun) in rule.lua_bindings(&lua) + if let Some(bindings) = rule.lua_bindings(&lua) { - table.set(fun_name, fun).unwrap(); - } + let table = lua.create_table().unwrap(); + let name = rule.name().to_lowercase(); - nml_table.set(name, table).unwrap(); + for (fun_name, fun) in bindings + { + table.set(fun_name, fun).unwrap(); + } + + nml_table.set(name, table).unwrap(); + } } lua.globals().set("nml", nml_table).unwrap(); } diff --git a/src/parser/rule.rs b/src/parser/rule.rs index 0769b19..cdb7c5a 100644 --- a/src/parser/rule.rs +++ b/src/parser/rule.rs @@ -25,7 +25,7 @@ pub trait Rule { match_data: Option>, ) -> (Cursor, Vec, Range)>>); /// Export bindings to lua - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)>; + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>>; } impl core::fmt::Debug for dyn Rule { @@ -89,7 +89,7 @@ pub trait RegexRule { matches: regex::Captures, ) -> Vec, Range)>>; - fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)>; + fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option)>>; } impl Rule for T { @@ -144,7 +144,7 @@ impl Rule for T { ); } - fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { + fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option)>> { self.lua_bindings(lua) } }