Added bindings
This commit is contained in:
parent
7a2c19af66
commit
b814c57355
18 changed files with 370 additions and 264 deletions
|
@ -544,8 +544,7 @@ impl RegexRule for CodeRule {
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
|
||||||
let mut bindings = vec![];
|
let mut bindings = vec![];
|
||||||
bindings.push((
|
bindings.push((
|
||||||
"push_inline".to_string(),
|
"push_inline".to_string(),
|
||||||
|
@ -647,7 +646,7 @@ impl RegexRule for CodeRule {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
bindings
|
Some(bindings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,5 +80,5 @@ impl RegexRule for CommentRule {
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,5 +371,5 @@ impl RegexRule for GraphRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,5 +178,5 @@ impl RegexRule for ImportRule {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,5 +171,5 @@ impl RegexRule for LinkRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -337,5 +337,5 @@ impl Rule for ListRule
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
use ariadne::Label;
|
||||||
use ariadne::Report;
|
use ariadne::Report;
|
||||||
use ariadne::ReportKind;
|
use ariadne::ReportKind;
|
||||||
|
use mlua::Function;
|
||||||
|
use mlua::Lua;
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Match;
|
use regex::Match;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -518,9 +520,7 @@ impl RegexRule for MediaRule {
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua mlua::Lua) -> Vec<(String, mlua::Function<'lua>)> {
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -150,5 +150,5 @@ impl Rule for ParagraphRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ impl RegexRule for RawRule {
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||||
let mut bindings = vec![];
|
let mut bindings = vec![];
|
||||||
|
|
||||||
bindings.push((
|
bindings.push((
|
||||||
|
@ -270,7 +270,7 @@ impl RegexRule for RawRule {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
bindings
|
Some(bindings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
use ariadne::Label;
|
||||||
use ariadne::Report;
|
use ariadne::Report;
|
||||||
use ariadne::ReportKind;
|
use ariadne::ReportKind;
|
||||||
|
use mlua::Function;
|
||||||
|
use mlua::Lua;
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
use regex::Match;
|
use regex::Match;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
@ -205,7 +207,5 @@ impl RegexRule for ReferenceRule {
|
||||||
reports
|
reports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua mlua::Lua) -> Vec<(String, mlua::Function<'lua>)> {
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,5 +275,5 @@ impl RegexRule for ScriptRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,7 +235,7 @@ impl RegexRule for SectionRule {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||||
let mut bindings = vec![];
|
let mut bindings = vec![];
|
||||||
|
|
||||||
bindings.push((
|
bindings.push((
|
||||||
|
@ -280,6 +280,6 @@ impl RegexRule for SectionRule {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
bindings
|
Some(bindings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,5 +183,5 @@ impl RegexRule for StyleRule
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
}
|
}
|
||||||
|
|
|
@ -430,7 +430,7 @@ impl RegexRule for TexRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -61,7 +61,7 @@ impl Rule for TextRule {
|
||||||
panic!("Text cannot match");
|
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<Vec<(String, Function<'lua>)>> {
|
||||||
let mut bindings = vec![];
|
let mut bindings = vec![];
|
||||||
bindings.push((
|
bindings.push((
|
||||||
"push".to_string(),
|
"push".to_string(),
|
||||||
|
@ -83,6 +83,6 @@ impl Rule for TextRule {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
));
|
));
|
||||||
|
|
||||||
bindings
|
Some(bindings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,41 @@
|
||||||
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 regex::Regex;
|
||||||
use crate::{document::document::Document, parser::{parser::{Parser, ReportColors}, rule::RegexRule, source::{Source, Token}}};
|
use std::ops::Range;
|
||||||
use ariadne::{Report, Fmt, Label, ReportKind};
|
use std::rc::Rc;
|
||||||
use crate::document::variable::{BaseVariable, PathVariable, Variable};
|
use std::str::FromStr;
|
||||||
use std::{ops::Range, rc::Rc};
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum VariableKind {
|
||||||
|
Regular,
|
||||||
|
Path,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for VariableKind {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"regular" | "" => Ok(VariableKind::Regular),
|
||||||
|
"path" | "'" => Ok(VariableKind::Path),
|
||||||
|
_ => Err(format!("Uknnown variable kind: `{s}`")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct VariableRule {
|
pub struct VariableRule {
|
||||||
re: [Regex; 1],
|
re: [Regex; 1],
|
||||||
|
@ -14,20 +46,20 @@ impl VariableRule {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
re: [Regex::new(r"(?:^|\n)@([^[:alpha:]])?(.*?)=((?:\\\n|.)*)").unwrap()],
|
re: [Regex::new(r"(?:^|\n)@([^[:alpha:]])?(.*?)=((?:\\\n|.)*)").unwrap()],
|
||||||
kinds: vec![
|
kinds: vec![("".into(), "Regular".into()), ("'".into(), "Path".into())],
|
||||||
("".into(), "Regular".into()),
|
|
||||||
("'".into(), "Path".into())
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_variable(&self, colors: &ReportColors, location: Token, kind: usize, name: String, value: String) -> Result<Rc<dyn Variable>, String>
|
pub fn make_variable(
|
||||||
{
|
&self,
|
||||||
match self.kinds[kind].0.as_str()
|
colors: &ReportColors,
|
||||||
{
|
location: Token,
|
||||||
"" => {
|
kind: usize,
|
||||||
Ok(Rc::new(BaseVariable::new(location, name, value)))
|
name: String,
|
||||||
}
|
value: String,
|
||||||
|
) -> Result<Rc<dyn Variable>, 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
|
match std::fs::canonicalize(value.as_str()) // TODO: not canonicalize
|
||||||
{
|
{
|
||||||
|
@ -37,33 +69,33 @@ impl VariableRule {
|
||||||
e.to_string()))
|
e.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("Unhandled variable kind")
|
_ => panic!("Unhandled variable kind"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim and check variable name for validity
|
// Trim and check variable name for validity
|
||||||
pub fn validate_name<'a>(colors: &ReportColors, original_name: &'a str) -> Result<&'a str, String>
|
pub fn validate_name<'a>(
|
||||||
{
|
colors: &ReportColors,
|
||||||
|
original_name: &'a str,
|
||||||
|
) -> Result<&'a str, String> {
|
||||||
let name = original_name.trim_start().trim_end();
|
let name = original_name.trim_start().trim_end();
|
||||||
if name.contains("%")
|
if name.contains("%") {
|
||||||
{
|
return Err(format!("Name cannot contain '{}'", "%".fg(colors.info)));
|
||||||
return Err(format!("Name cannot contain '{}'",
|
|
||||||
"%".fg(colors.info)));
|
|
||||||
}
|
}
|
||||||
return Ok(name);
|
return Ok(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_value(_colors: &ReportColors, original_value: &str) -> Result<String, String>
|
pub fn validate_value(_colors: &ReportColors, original_value: &str) -> Result<String, String> {
|
||||||
{
|
|
||||||
let mut escaped = 0usize;
|
let mut escaped = 0usize;
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
for c in original_value.trim_start().trim_end().chars() {
|
for c in original_value.trim_start().trim_end().chars() {
|
||||||
if c == '\\' { escaped += 1 }
|
if c == '\\' {
|
||||||
else if c == '\n' {
|
escaped += 1
|
||||||
|
} else if c == '\n' {
|
||||||
match escaped {
|
match escaped {
|
||||||
0 => return Err("Unknown error wile capturing variable".to_string()),
|
0 => return Err("Unknown error wile capturing variable".to_string()),
|
||||||
// Remove '\n'
|
// Remove '\n'
|
||||||
1 => {},
|
1 => {}
|
||||||
// Insert '\n'
|
// Insert '\n'
|
||||||
_ => {
|
_ => {
|
||||||
result.push(c);
|
result.push(c);
|
||||||
|
@ -71,8 +103,7 @@ impl VariableRule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
escaped = 0;
|
escaped = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
(0..escaped).for_each(|_| result.push('\\'));
|
(0..escaped).for_each(|_| result.push('\\'));
|
||||||
escaped = 0;
|
escaped = 0;
|
||||||
result.push(c);
|
result.push(c);
|
||||||
|
@ -89,35 +120,54 @@ impl RegexRule for VariableRule {
|
||||||
|
|
||||||
fn regexes(&self) -> &[Regex] { &self.re }
|
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<Report<'_, (Rc<dyn Source>, Range<usize>)>>
|
fn on_regex_match<'a>(
|
||||||
{
|
&self,
|
||||||
|
_: usize,
|
||||||
|
parser: &dyn Parser,
|
||||||
|
document: &'a dyn Document,
|
||||||
|
token: Token,
|
||||||
|
matches: regex::Captures,
|
||||||
|
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
// [Optional] variable kind
|
// [Optional] variable kind
|
||||||
let var_kind = match matches.get(1)
|
let var_kind = match matches.get(1) {
|
||||||
{
|
|
||||||
Some(kind) => {
|
Some(kind) => {
|
||||||
// Find kind
|
// Find kind
|
||||||
let r = self.kinds.iter().enumerate().find(|(_i, (ref char, ref _name))| {
|
let r = self
|
||||||
char == kind.as_str() });
|
.kinds
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_i, (ref char, ref _name))| char == kind.as_str());
|
||||||
|
|
||||||
// Unknown kind specified
|
// Unknown kind specified
|
||||||
if r.is_none()
|
if r.is_none() {
|
||||||
{
|
|
||||||
result.push(
|
result.push(
|
||||||
Report::build(ReportKind::Error, token.source(), kind.start())
|
Report::build(ReportKind::Error, token.source(), kind.start())
|
||||||
.with_message("Unknown variable kind")
|
.with_message("Unknown variable kind")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), kind.range()))
|
Label::new((token.source(), kind.range()))
|
||||||
.with_message(format!("Variable kind `{}` is unknown",
|
.with_message(format!(
|
||||||
kind.as_str().fg(parser.colors().highlight)))
|
"Variable kind `{}` is unknown",
|
||||||
.with_color(parser.colors().error))
|
kind.as_str().fg(parser.colors().highlight)
|
||||||
.with_help(format!("Leave empty for regular variables. Available variable kinds:{}",
|
))
|
||||||
self.kinds.iter().skip(1).fold("".to_string(), |acc, (char, name)| {
|
.with_color(parser.colors().error),
|
||||||
acc + format!("\n - `{}` : {}",
|
)
|
||||||
|
.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),
|
char.fg(parser.colors().highlight),
|
||||||
name.fg(parser.colors().info)).as_str()
|
name.fg(parser.colors().info)
|
||||||
})))
|
)
|
||||||
.finish());
|
.as_str()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
))
|
||||||
|
.finish(),
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -127,11 +177,8 @@ impl RegexRule for VariableRule {
|
||||||
None => 0,
|
None => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let var_name = match matches.get(2)
|
let var_name = match matches.get(2) {
|
||||||
{
|
Some(name) => match VariableRule::validate_name(&parser.colors(), name.as_str()) {
|
||||||
Some(name) => {
|
|
||||||
match VariableRule::validate_name(&parser.colors(), name.as_str())
|
|
||||||
{
|
|
||||||
Ok(var_name) => var_name,
|
Ok(var_name) => var_name,
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
result.push(
|
result.push(
|
||||||
|
@ -139,23 +186,23 @@ impl RegexRule for VariableRule {
|
||||||
.with_message("Invalid variable name")
|
.with_message("Invalid variable name")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), name.range()))
|
Label::new((token.source(), name.range()))
|
||||||
.with_message(format!("Variable name `{}` is not allowed. {msg}",
|
.with_message(format!(
|
||||||
name.as_str().fg(parser.colors().highlight)))
|
"Variable name `{}` is not allowed. {msg}",
|
||||||
.with_color(parser.colors().error))
|
name.as_str().fg(parser.colors().highlight)
|
||||||
.finish());
|
))
|
||||||
|
.with_color(parser.colors().error),
|
||||||
|
)
|
||||||
|
.finish(),
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => panic!("Unknown variable name")
|
_ => panic!("Unknown variable name"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let var_value = match matches.get(3)
|
let var_value = match matches.get(3) {
|
||||||
{
|
Some(value) => match VariableRule::validate_value(&parser.colors(), value.as_str()) {
|
||||||
Some(value) => {
|
|
||||||
match VariableRule::validate_value(&parser.colors(), value.as_str())
|
|
||||||
{
|
|
||||||
Ok(var_value) => var_value,
|
Ok(var_value) => var_value,
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
result.push(
|
result.push(
|
||||||
|
@ -163,20 +210,28 @@ impl RegexRule for VariableRule {
|
||||||
.with_message("Invalid variable value")
|
.with_message("Invalid variable value")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), value.range()))
|
Label::new((token.source(), value.range()))
|
||||||
.with_message(format!("Variable value `{}` is not allowed. {msg}",
|
.with_message(format!(
|
||||||
value.as_str().fg(parser.colors().highlight)))
|
"Variable value `{}` is not allowed. {msg}",
|
||||||
.with_color(parser.colors().error))
|
value.as_str().fg(parser.colors().highlight)
|
||||||
.finish());
|
))
|
||||||
|
.with_color(parser.colors().error),
|
||||||
|
)
|
||||||
|
.finish(),
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
_ => panic!("Invalid variable value"),
|
||||||
_ => panic!("Invalid variable value")
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.make_variable(&parser.colors(), token.clone(), var_kind, var_name.to_string(), var_value)
|
match self.make_variable(
|
||||||
{
|
&parser.colors(),
|
||||||
|
token.clone(),
|
||||||
|
var_kind,
|
||||||
|
var_name.to_string(),
|
||||||
|
var_value,
|
||||||
|
) {
|
||||||
Ok(variable) => document.add_variable(variable),
|
Ok(variable) => document.add_variable(variable),
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
let m = matches.get(0).unwrap();
|
let m = matches.get(0).unwrap();
|
||||||
|
@ -185,11 +240,15 @@ impl RegexRule for VariableRule {
|
||||||
.with_message("Unable to create variable")
|
.with_message("Unable to create variable")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), m.start() + 1..m.end()))
|
Label::new((token.source(), m.start() + 1..m.end()))
|
||||||
.with_message(format!("Unable to create variable `{}`. {}",
|
.with_message(format!(
|
||||||
|
"Unable to create variable `{}`. {}",
|
||||||
var_name.fg(parser.colors().highlight),
|
var_name.fg(parser.colors().highlight),
|
||||||
msg))
|
msg
|
||||||
.with_color(parser.colors().error))
|
))
|
||||||
.finish());
|
.with_color(parser.colors().error),
|
||||||
|
)
|
||||||
|
.finish(),
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -198,12 +257,45 @@ impl RegexRule for VariableRule {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
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);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
pub struct VariableSubstitutionRule
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
|
bindings.push((
|
||||||
|
"get".to_string(),
|
||||||
|
lua.create_function(|_, name: String| {
|
||||||
|
let mut value: Option<String> = 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 {
|
||||||
re: [Regex; 1],
|
re: [Regex; 1],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,100 +307,113 @@ impl VariableSubstitutionRule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegexRule for VariableSubstitutionRule
|
impl RegexRule for VariableSubstitutionRule {
|
||||||
{
|
|
||||||
fn name(&self) -> &'static str { "Variable Substitution" }
|
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<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
fn on_regex_match<'a>(
|
||||||
|
&self,
|
||||||
|
_index: usize,
|
||||||
|
parser: &dyn Parser,
|
||||||
|
document: &'a dyn Document<'a>,
|
||||||
|
token: Token,
|
||||||
|
matches: regex::Captures,
|
||||||
|
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>> {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
|
|
||||||
let variable = match matches.get(1)
|
let variable = match matches.get(1) {
|
||||||
{
|
|
||||||
Some(name) => {
|
Some(name) => {
|
||||||
// Empty name
|
// Empty name
|
||||||
if name.as_str().is_empty()
|
if name.as_str().is_empty() {
|
||||||
{
|
|
||||||
result.push(
|
result.push(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_message("Empty variable name")
|
.with_message("Empty variable name")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), matches.get(0).unwrap().range()))
|
Label::new((token.source(), matches.get(0).unwrap().range()))
|
||||||
.with_message(format!("Missing variable name for substitution"))
|
.with_message(format!("Missing variable name for substitution"))
|
||||||
.with_color(parser.colors().error))
|
.with_color(parser.colors().error),
|
||||||
.finish());
|
)
|
||||||
|
.finish(),
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// Leading spaces
|
// Leading spaces
|
||||||
else if name.as_str().trim_start() != name.as_str()
|
else if name.as_str().trim_start() != name.as_str() {
|
||||||
{
|
|
||||||
result.push(
|
result.push(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_message("Invalid variable name")
|
.with_message("Invalid variable name")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), name.range()))
|
Label::new((token.source(), name.range()))
|
||||||
.with_message(format!("Variable names contains leading spaces"))
|
.with_message(format!("Variable names contains leading spaces"))
|
||||||
.with_color(parser.colors().error))
|
.with_color(parser.colors().error),
|
||||||
|
)
|
||||||
.with_help("Remove leading spaces")
|
.with_help("Remove leading spaces")
|
||||||
.finish());
|
.finish(),
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// Trailing spaces
|
// Trailing spaces
|
||||||
else if name.as_str().trim_end() != name.as_str()
|
else if name.as_str().trim_end() != name.as_str() {
|
||||||
{
|
|
||||||
result.push(
|
result.push(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_message("Invalid variable name")
|
.with_message("Invalid variable name")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), name.range()))
|
Label::new((token.source(), name.range()))
|
||||||
.with_message(format!("Variable names contains trailing spaces"))
|
.with_message(format!(
|
||||||
.with_color(parser.colors().error))
|
"Variable names contains trailing spaces"
|
||||||
|
))
|
||||||
|
.with_color(parser.colors().error),
|
||||||
|
)
|
||||||
.with_help("Remove trailing spaces")
|
.with_help("Remove trailing spaces")
|
||||||
.finish());
|
.finish(),
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// Invalid name
|
// Invalid name
|
||||||
match VariableRule::validate_name(&parser.colors(), name.as_str())
|
match VariableRule::validate_name(&parser.colors(), name.as_str()) {
|
||||||
{
|
Err(msg) => {
|
||||||
Err(msg) =>
|
|
||||||
{
|
|
||||||
result.push(
|
result.push(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_message("Invalid variable name")
|
.with_message("Invalid variable name")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), name.range()))
|
Label::new((token.source(), name.range()))
|
||||||
.with_message(msg)
|
.with_message(msg)
|
||||||
.with_color(parser.colors().error))
|
.with_color(parser.colors().error),
|
||||||
.finish());
|
)
|
||||||
|
.finish(),
|
||||||
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get variable
|
// Get variable
|
||||||
match document.get_variable(name.as_str())
|
match document.get_variable(name.as_str()) {
|
||||||
{
|
|
||||||
None => {
|
None => {
|
||||||
result.push(
|
result.push(
|
||||||
Report::build(ReportKind::Error, token.source(), name.start())
|
Report::build(ReportKind::Error, token.source(), name.start())
|
||||||
.with_message("Unknown variable name")
|
.with_message("Unknown variable name")
|
||||||
.with_label(
|
.with_label(
|
||||||
Label::new((token.source(), name.range()))
|
Label::new((token.source(), name.range()))
|
||||||
.with_message(format!("Unable to find variable with name: `{}`",
|
.with_message(format!(
|
||||||
name.as_str().fg(parser.colors().highlight)))
|
"Unable to find variable with name: `{}`",
|
||||||
.with_color(parser.colors().error))
|
name.as_str().fg(parser.colors().highlight)
|
||||||
.finish());
|
))
|
||||||
|
.with_color(parser.colors().error),
|
||||||
|
)
|
||||||
|
.finish(),
|
||||||
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
Some(var) => var,
|
Some(var) => var,
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => panic!("Unknown error")
|
_ => panic!("Unknown error"),
|
||||||
};
|
};
|
||||||
|
|
||||||
variable.parse(token, parser, document);
|
variable.parse(token, parser, document);
|
||||||
|
@ -316,6 +421,5 @@ impl RegexRule for VariableSubstitutionRule
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> { None }
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)> { vec![] }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,17 +33,20 @@ impl Kernel {
|
||||||
let nml_table = lua.create_table().unwrap();
|
let nml_table = lua.create_table().unwrap();
|
||||||
|
|
||||||
for rule in parser.rules()
|
for rule in parser.rules()
|
||||||
|
{
|
||||||
|
if let Some(bindings) = rule.lua_bindings(&lua)
|
||||||
{
|
{
|
||||||
let table = lua.create_table().unwrap();
|
let table = lua.create_table().unwrap();
|
||||||
let name = rule.name().to_lowercase();
|
let name = rule.name().to_lowercase();
|
||||||
|
|
||||||
for (fun_name, fun) in rule.lua_bindings(&lua)
|
for (fun_name, fun) in bindings
|
||||||
{
|
{
|
||||||
table.set(fun_name, fun).unwrap();
|
table.set(fun_name, fun).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
nml_table.set(name, table).unwrap();
|
nml_table.set(name, table).unwrap();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
lua.globals().set("nml", nml_table).unwrap();
|
lua.globals().set("nml", nml_table).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub trait Rule {
|
||||||
match_data: Option<Box<dyn Any>>,
|
match_data: Option<Box<dyn Any>>,
|
||||||
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>);
|
) -> (Cursor, Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>);
|
||||||
/// Export bindings to lua
|
/// 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<Vec<(String, Function<'lua>)>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for dyn Rule {
|
impl core::fmt::Debug for dyn Rule {
|
||||||
|
@ -89,7 +89,7 @@ pub trait RegexRule {
|
||||||
matches: regex::Captures,
|
matches: regex::Captures,
|
||||||
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>;
|
) -> Vec<Report<'_, (Rc<dyn Source>, Range<usize>)>>;
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Vec<(String, Function<'lua>)>;
|
fn lua_bindings<'lua>(&self, _lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RegexRule> Rule for T {
|
impl<T: RegexRule> Rule for T {
|
||||||
|
@ -144,7 +144,7 @@ impl<T: RegexRule> Rule for T {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Vec<(String, Function<'lua>)> {
|
fn lua_bindings<'lua>(&self, lua: &'lua Lua) -> Option<Vec<(String, Function<'lua>)>> {
|
||||||
self.lua_bindings(lua)
|
self.lua_bindings(lua)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue