Skip to content

Commit

Permalink
Modify extensions for better legacy support
Browse files Browse the repository at this point in the history
  • Loading branch information
rscarson committed Oct 23, 2023
1 parent ef6bada commit 71eea1b
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 146 deletions.
124 changes: 30 additions & 94 deletions src/extensions/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,12 @@ pub struct Extension {
pub version: String,

#[serde(default)]
/// Defines all the functions provided by this extension
pub function_definitions: Option<HashMap<String, ExtensionFunction>>,
/// Functions supported by this extension
pub functions: HashMap<String, ExtensionFunction>,

#[serde(default)]
/// Defines all the decorators provided by this extension
pub decorator_definitions: Option<HashMap<String, ExtensionFunction>>,

#[serde(default)]
/// Legacy extension support
pub functions: Option<HashMap<String, String>>,

#[serde(default)]
/// Legacy extension support
pub decorators: Option<HashMap<String, String>>,
/// Decorators supported by this extension
pub decorators: HashMap<String, ExtensionFunction>,
}

impl std::fmt::Display for Extension {
Expand All @@ -73,14 +65,7 @@ impl Extension {
/// # Arguments
/// * `name` - Function name
pub fn has_function(&self, name: &str) -> bool {
if let Some(functions) = &self.function_definitions {
functions.contains_key(name)
} else if let Some(functions) = &self.functions {
// Legacy function support
functions.contains_key(name)
} else {
false
}
self.functions.contains_key(name)
}

/// Call a function from the extension
Expand All @@ -94,37 +79,19 @@ impl Extension {
args: &[Value],
variables: &mut HashMap<String, Value>,
) -> Result<Value, rustyscript::Error> {
if let Some(functions) = &self.function_definitions {
let function_properties = functions
.get(name)
.ok_or(rustyscript::Error::ValueNotFound(name.to_string()))?;
function_properties.call(&self.module, args, variables)
} else if let Some(functions) = &self.functions {
// Legacy function support
let function_name = functions
.get(name)
.ok_or(rustyscript::Error::ValueNotFound(name.to_string()))?;
ExtensionFunction::call_legacy(function_name, &self.module, args)
} else {
Err(rustyscript::Error::JsonDecode(
"invalid extension definition".to_string(),
))
}
let function_properties = self
.functions
.get(name)
.ok_or(rustyscript::Error::ValueNotFound(name.to_string()))?;
function_properties.call(&self.module, args, variables)
}

/// Determine if a decorator exists in the extension
///
/// # Arguments
/// * `name` - Decorator name
pub fn has_decorator(&self, name: &str) -> bool {
if let Some(decorators) = &self.decorator_definitions {
decorators.contains_key(name)
} else if let Some(decorators) = &self.decorators {
// Legacy function support
decorators.contains_key(name)
} else {
false
}
self.decorators.contains_key(name)
}

/// Call a decorator from the extension
Expand All @@ -138,24 +105,13 @@ impl Extension {
token: &Token,
variables: &mut HashMap<String, Value>,
) -> Result<String, rustyscript::Error> {
if let Some(decorator) = &self.decorator_definitions {
let function_properties = decorator
.get(name)
.ok_or(rustyscript::Error::ValueNotFound(name.to_string()))?;
Ok(function_properties
.call(&self.module, &[token.value()], variables)?
.to_string())
} else if let Some(decorator) = &self.decorators {
// Legacy function support
let function_name = decorator
.get(name)
.ok_or(rustyscript::Error::ValueNotFound(name.to_string()))?;
ExtensionFunction::call_legacy_decorator(function_name, &self.module, token.value())
} else {
Err(rustyscript::Error::JsonDecode(
"invalid extension definition".to_string(),
))
}
let function_properties = self
.decorators
.get(name)
.ok_or(rustyscript::Error::ValueNotFound(name.to_string()))?;
function_properties
.call(&self.module, &[token.value()], variables)
.and_then(|v| Ok(v.to_string()))
}

/// Returns the file from which an extension was loaded
Expand All @@ -180,56 +136,36 @@ impl Extension {

/// Return the list of all functions in the extension
pub fn functions(&self) -> Vec<String> {
let mut function_keys = if let Some(functions) = &self.function_definitions {
functions.keys().cloned().collect()
} else if let Some(functions) = &self.functions {
functions.keys().cloned().collect()
} else {
vec![]
};

let mut function_keys: Vec<String> = self.functions.keys().cloned().collect();
function_keys.sort();
function_keys
}

/// Return the list of all functions, with complete signatures
pub fn function_signatures(&self) -> Vec<String> {
let mut function_keys = if let Some(functions) = &self.function_definitions {
functions.values().map(|k| k.signature()).collect()
} else if let Some(functions) = &self.functions {
functions.keys().map(|k| format!("{}()", k)).collect()
} else {
vec![]
};

let mut function_keys: Vec<String> = self
.functions
.values()
.map(|k| k.function_signature())
.collect();
function_keys.sort();
function_keys
}

/// Return the list of all decorators in the extension
pub fn decorators(&self) -> Vec<String> {
let mut decorator_keys = if let Some(decorators) = &self.decorator_definitions {
decorators.keys().cloned().collect()
} else if let Some(decorators) = &self.decorators {
decorators.keys().cloned().collect()
} else {
vec![]
};

let mut decorator_keys: Vec<String> = self.decorators.keys().cloned().collect();
decorator_keys.sort();
decorator_keys
}

/// Return the list of all decorators, with complete signatures
pub fn decorator_signatures(&self) -> Vec<String> {
let mut decorator_keys = if let Some(decorators) = &self.decorator_definitions {
decorators.values().map(|k| k.signature()).collect()
} else if let Some(decorators) = &self.decorators {
decorators.keys().map(|k| format!("@{}", k)).collect()
} else {
vec![]
};

let mut decorator_keys: Vec<String> = self
.decorators
.values()
.map(|k| k.decorator_signature())
.collect();
decorator_keys.sort();
decorator_keys
}
Expand Down
103 changes: 60 additions & 43 deletions src/extensions/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,51 @@ use std::collections::HashMap;
use super::runtime::ExtensionsRuntime;

#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)]
pub struct ExtensionFunction {
pub struct ExtensionFunctionDefinition {
pub returns: String,
pub argument_types: Vec<String>,
pub fname: String,
pub ftype: String,
}

impl ExtensionFunction {
fn decorator_signature(&self) -> String {
format!(
"[{}] @{}",
self.argument_types
.get(0)
.unwrap_or(&"Any".to_string().to_lowercase()),
self.fname
)
}
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
#[serde(untagged)]
pub enum ExtensionFunction {
Legacy(String),
Standard(ExtensionFunctionDefinition),
}

fn function_signature(&self) -> String {
format!(
"{}({}) -> {}",
self.fname,
self.argument_types
.iter()
.map(|a| format!("[{}]", a.to_lowercase()))
.collect::<Vec<String>>()
.join(", "),
self.returns.to_lowercase()
)
impl ExtensionFunction {
pub fn decorator_signature(&self) -> String {
match self {
Self::Legacy(f) => format!("@{}", f),
Self::Standard(f) => format!(
"[{}] @{}",
f.argument_types
.get(0)
.unwrap_or(&"Any".to_string().to_lowercase()),
f.fname
),
}
}

pub fn signature(&self) -> String {
if self.ftype == "decorator" {
self.decorator_signature()
} else {
self.function_signature()
pub fn function_signature(&self) -> String {
match self {
Self::Legacy(f) => format!("{}( ... )", f),
Self::Standard(f) => format!(
"{}({}) -> {}",
f.fname,
f.argument_types
.iter()
.map(|a| format!("[{}]", a.to_lowercase()))
.collect::<Vec<String>>()
.join(", "),
f.returns.to_lowercase()
),
}
}

pub fn call_legacy(
fn call_legacy(
name: &str,
module: &Module,
args: &[Value],
Expand All @@ -60,21 +65,7 @@ impl ExtensionFunction {
})
}

pub fn call_legacy_decorator(
name: &str,
module: &Module,
arg: Value,
) -> Result<String, rustyscript::Error> {
ExtensionsRuntime::with(|runtime| match runtime.load_module(module) {
Ok(module_context) => {
let mut _arg = serde_json::to_value(arg.clone())?;
runtime.call_function::<String>(&module_context, name, &[_arg])
}
Err(e) => Err(e),
})
}

pub fn call(
fn call_standard(
&self,
module: &Module,
args: &[Value],
Expand Down Expand Up @@ -121,4 +112,30 @@ impl ExtensionFunction {
}
})
}

pub fn call_legacy_decorator(
name: &str,
module: &Module,
arg: Value,
) -> Result<String, rustyscript::Error> {
ExtensionsRuntime::with(|runtime| match runtime.load_module(module) {
Ok(module_context) => {
let mut _arg = serde_json::to_value(arg.clone())?;
runtime.call_function::<String>(&module_context, name, &[_arg])
}
Err(e) => Err(e),
})
}

pub fn call(
&self,
module: &Module,
args: &[Value],
variables: &mut HashMap<String, Value>,
) -> Result<Value, rustyscript::Error> {
match self {
Self::Legacy(f) => Self::call_legacy(f, module, args),
Self::Standard(_) => self.call_standard(module, args, variables),
}
}
}
8 changes: 4 additions & 4 deletions src/extensions/js/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,17 @@ export class LavendeuxExtension {

export() {
let properties = {
'function_definitions': {},
'decorator_definitions': {}
'functions': {},
'decorators': {}
};
Object.assign(properties, this.properties);

for (const name in this.functions) {
properties.function_definitions[name] = this.functions[name].properties;
properties.functions[name] = this.functions[name].properties;
}

for (const name in this.decorators) {
properties.decorator_definitions[name] = this.decorators[name].properties;
properties.decorators[name] = this.decorators[name].properties;
}

return properties;
Expand Down
1 change: 1 addition & 0 deletions src/extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ mod runtime;
mod table;

pub use extension::Extension;
pub use function::ExtensionFunction;
pub use table::ExtensionTable;
14 changes: 9 additions & 5 deletions src/functions/builtins/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ pub fn register_functions(table: &mut FunctionTable) {
mod test_token {
use super::*;

use crate::extensions::ExtensionFunction;
#[cfg(feature = "extensions")]
use crate::Extension;

Expand Down Expand Up @@ -213,11 +214,14 @@ mod test_token {
name: "Unnamed Extension".to_string(),
author: "@anon".to_string(),
version: "0.0.0".to_string(),
functions: Some(HashMap::from([("test".to_string(), "test2".to_string())])),
decorators: Some(HashMap::from([("test3".to_string(), "test4".to_string())])),

function_definitions: None,
decorator_definitions: None,
functions: HashMap::from([(
"test".to_string(),
ExtensionFunction::Legacy("test2".to_string()),
)]),
decorators: HashMap::from([(
"test3".to_string(),
ExtensionFunction::Legacy("test4".to_string()),
)]),
},
);

Expand Down

0 comments on commit 71eea1b

Please sign in to comment.