Implement context
This commit is contained in:
parent
d997bbd08a
commit
90c0304af5
@ -114,12 +114,11 @@ impl BuiltInValue {
|
|||||||
let key = fs_function.name().to_string();
|
let key = fs_function.name().to_string();
|
||||||
let value =
|
let value =
|
||||||
Value::Function(Function::BuiltIn(BuiltInFunction::Fs(fs_function)));
|
Value::Function(Function::BuiltIn(BuiltInFunction::Fs(fs_function)));
|
||||||
let r#type = value.r#type();
|
|
||||||
|
|
||||||
fs_context.insert(key, (value, r#type));
|
fs_context.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(Map::with_variables(fs_context))
|
Value::Map(Map::with_values(fs_context))
|
||||||
}),
|
}),
|
||||||
BuiltInValue::Json => JSON.get_or_init(|| {
|
BuiltInValue::Json => JSON.get_or_init(|| {
|
||||||
let mut json_context = BTreeMap::new();
|
let mut json_context = BTreeMap::new();
|
||||||
@ -128,12 +127,11 @@ impl BuiltInValue {
|
|||||||
let key = json_function.name().to_string();
|
let key = json_function.name().to_string();
|
||||||
let value =
|
let value =
|
||||||
Value::Function(Function::BuiltIn(BuiltInFunction::Json(json_function)));
|
Value::Function(Function::BuiltIn(BuiltInFunction::Json(json_function)));
|
||||||
let r#type = value.r#type();
|
|
||||||
|
|
||||||
json_context.insert(key, (value, r#type));
|
json_context.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(Map::with_variables(json_context))
|
Value::Map(Map::with_values(json_context))
|
||||||
}),
|
}),
|
||||||
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
|
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
|
||||||
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
||||||
@ -148,12 +146,11 @@ impl BuiltInValue {
|
|||||||
] {
|
] {
|
||||||
let key = built_in_function.name().to_string();
|
let key = built_in_function.name().to_string();
|
||||||
let value = Value::Function(Function::BuiltIn(built_in_function));
|
let value = Value::Function(Function::BuiltIn(built_in_function));
|
||||||
let r#type = built_in_function.r#type();
|
|
||||||
|
|
||||||
random_context.insert(key, (value, r#type));
|
random_context.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(Map::with_variables(random_context))
|
Value::Map(Map::with_values(random_context))
|
||||||
}),
|
}),
|
||||||
BuiltInValue::Str => STRING.get_or_init(|| {
|
BuiltInValue::Str => STRING.get_or_init(|| {
|
||||||
let mut string_context = BTreeMap::new();
|
let mut string_context = BTreeMap::new();
|
||||||
@ -163,12 +160,11 @@ impl BuiltInValue {
|
|||||||
let value = Value::Function(Function::BuiltIn(BuiltInFunction::String(
|
let value = Value::Function(Function::BuiltIn(BuiltInFunction::String(
|
||||||
string_function,
|
string_function,
|
||||||
)));
|
)));
|
||||||
let r#type = string_function.r#type();
|
|
||||||
|
|
||||||
string_context.insert(key, (value, r#type));
|
string_context.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(Map::with_variables(string_context))
|
Value::Map(Map::with_values(string_context))
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,21 +86,13 @@ impl AbstractTree for Index {
|
|||||||
Value::Map(map) => {
|
Value::Map(map) => {
|
||||||
let (key, value) = if let IndexExpression::Identifier(identifier) = &self.index {
|
let (key, value) = if let IndexExpression::Identifier(identifier) = &self.index {
|
||||||
let key = identifier.inner();
|
let key = identifier.inner();
|
||||||
let value = map
|
let value = map.get(key).unwrap_or_default();
|
||||||
.variables()?
|
|
||||||
.get(key)
|
|
||||||
.map(|(value, _)| value.clone())
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
(key.clone(), value)
|
(key.clone(), value)
|
||||||
} else {
|
} else {
|
||||||
let index_value = self.index.run(source, context)?;
|
let index_value = self.index.run(source, context)?;
|
||||||
let key = index_value.as_string()?;
|
let key = index_value.as_string()?;
|
||||||
let value = map
|
let value = map.get(key.as_str()).unwrap_or_default();
|
||||||
.variables()?
|
|
||||||
.get(key.as_str())
|
|
||||||
.map(|(value, _)| value.clone())
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
(key.clone(), value)
|
(key.clone(), value)
|
||||||
};
|
};
|
||||||
@ -108,7 +100,7 @@ impl AbstractTree for Index {
|
|||||||
if value.is_none() {
|
if value.is_none() {
|
||||||
Err(RuntimeError::VariableIdentifierNotFound(key))
|
Err(RuntimeError::VariableIdentifierNotFound(key))
|
||||||
} else {
|
} else {
|
||||||
Ok(value)
|
Ok(value.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::String(string) => {
|
Value::String(string) => {
|
||||||
|
@ -43,7 +43,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||||
let index_collection = self.index.collection.run(source, context)?;
|
let _index_collection = self.index.collection.run(source, context)?;
|
||||||
let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
||||||
identifier.inner()
|
identifier.inner()
|
||||||
} else {
|
} else {
|
||||||
|
@ -242,7 +242,7 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ValueNode::Map(statements, source_position) => {
|
ValueNode::Map(statements, source_position) => {
|
||||||
for (key, (statement, r#type)) in statements {
|
for (_key, (statement, r#type)) in statements {
|
||||||
if let Some(expected) = r#type {
|
if let Some(expected) = r#type {
|
||||||
let actual = statement.expected_type(context)?;
|
let actual = statement.expected_type(context)?;
|
||||||
|
|
||||||
@ -294,13 +294,13 @@ impl AbstractTree for ValueNode {
|
|||||||
Value::Option(option_value)
|
Value::Option(option_value)
|
||||||
}
|
}
|
||||||
ValueNode::Map(key_statement_pairs, _) => {
|
ValueNode::Map(key_statement_pairs, _) => {
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
for (key, (statement, _)) in key_statement_pairs {
|
for (key, (statement, _)) in key_statement_pairs {
|
||||||
let value = statement.run(source, context)?;
|
let value = statement.run(source, context)?;
|
||||||
|
|
||||||
map.set(key.clone(), value)?;
|
map.set(key.clone(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ impl Callable for BuiltInFunction {
|
|||||||
let length = if let Ok(list) = value.as_list() {
|
let length = if let Ok(list) = value.as_list() {
|
||||||
list.items().len()
|
list.items().len()
|
||||||
} else if let Ok(map) = value.as_map() {
|
} else if let Ok(map) = value.as_map() {
|
||||||
map.variables()?.len()
|
map.len()
|
||||||
} else if let Ok(str) = value.as_string() {
|
} else if let Ok(str) = value.as_string() {
|
||||||
str.chars().count()
|
str.chars().count()
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock, RwLockReadGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{error::rw_lock_error::RwLockError, Type, Value};
|
use crate::{error::rw_lock_error::RwLockError, Type, Value};
|
||||||
@ -16,6 +16,7 @@ pub enum ValueData {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
inner: Arc<RwLock<HashMap<String, ValueData>>>,
|
inner: Arc<RwLock<HashMap<String, ValueData>>>,
|
||||||
}
|
}
|
||||||
@ -27,6 +28,10 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inner(&self) -> Result<RwLockReadGuard<HashMap<String, ValueData>>, RwLockError> {
|
||||||
|
Ok(self.inner.read()?)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn inherit_from(other: &Context) -> Result<Context, RwLockError> {
|
pub fn inherit_from(other: &Context) -> Result<Context, RwLockError> {
|
||||||
let mut new_variables = HashMap::new();
|
let mut new_variables = HashMap::new();
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ pub use runtime_error::RuntimeError;
|
|||||||
pub use syntax_error::SyntaxError;
|
pub use syntax_error::SyntaxError;
|
||||||
pub use validation_error::ValidationError;
|
pub use validation_error::ValidationError;
|
||||||
|
|
||||||
use tree_sitter::{LanguageError, Point};
|
use tree_sitter::LanguageError;
|
||||||
|
|
||||||
use std::fmt::{self, Formatter};
|
use std::fmt::{self, Formatter};
|
||||||
|
|
||||||
@ -69,11 +69,7 @@ impl fmt::Display for Error {
|
|||||||
Validation(error) => write!(f, "Validation error: {error}"),
|
Validation(error) => write!(f, "Validation error: {error}"),
|
||||||
Runtime(error) => write!(f, "Runtime error: {error}"),
|
Runtime(error) => write!(f, "Runtime error: {error}"),
|
||||||
ParserCancelled => write!(f, "Parsing was cancelled because the parser took too long."),
|
ParserCancelled => write!(f, "Parsing was cancelled because the parser took too long."),
|
||||||
Language(error) => write!(f, "Parser failed to load language grammar."),
|
Language(_error) => write!(f, "Parser failed to load language grammar."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_position(position: &Point) -> String {
|
|
||||||
format!("column {}, row {}", position.row + 1, position.column)
|
|
||||||
}
|
|
||||||
|
@ -5,8 +5,12 @@
|
|||||||
//! You can use this library externally by calling either of the "interpret"
|
//! You can use this library externally by calling either of the "interpret"
|
||||||
//! functions or by constructing your own Interpreter.
|
//! functions or by constructing your own Interpreter.
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
abstract_tree::*, built_in_functions::BuiltInFunction, context::Context, error::Error,
|
abstract_tree::*,
|
||||||
interpret::*, value::*,
|
built_in_functions::BuiltInFunction,
|
||||||
|
context::{Context, ValueData},
|
||||||
|
error::Error,
|
||||||
|
interpret::*,
|
||||||
|
value::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use tree_sitter::Node as SyntaxNode;
|
pub use tree_sitter::Node as SyntaxNode;
|
||||||
|
52
src/main.rs
52
src/main.rs
@ -11,7 +11,7 @@ use reedline::{
|
|||||||
|
|
||||||
use std::{borrow::Cow, fs::read_to_string, path::PathBuf, process::Command};
|
use std::{borrow::Cow, fs::read_to_string, path::PathBuf, process::Command};
|
||||||
|
|
||||||
use dust_lang::{built_in_values, Error, Interpreter, Map, Value};
|
use dust_lang::{built_in_values, Context, Error, Interpreter, Value, ValueData};
|
||||||
|
|
||||||
/// Command-line arguments to be parsed.
|
/// Command-line arguments to be parsed.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@ -50,11 +50,11 @@ fn main() {
|
|||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let context = Map::new();
|
let context = Context::new();
|
||||||
|
|
||||||
if let Some(input) = args.input {
|
if let Some(input) = args.input {
|
||||||
context
|
context
|
||||||
.set("input".to_string(), Value::string(input))
|
.set_value("input".to_string(), Value::string(input))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ fn main() {
|
|||||||
let file_contents = read_to_string(path).unwrap();
|
let file_contents = read_to_string(path).unwrap();
|
||||||
|
|
||||||
context
|
context
|
||||||
.set("input".to_string(), Value::string(file_contents))
|
.set_value("input".to_string(), Value::string(file_contents))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,11 +117,11 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct DustHighlighter {
|
struct DustHighlighter {
|
||||||
context: Map,
|
context: Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DustHighlighter {
|
impl DustHighlighter {
|
||||||
fn new(context: Map) -> Self {
|
fn new(context: Context) -> Self {
|
||||||
Self { context }
|
Self { context }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,36 +130,27 @@ const HIGHLIGHT_TERMINATORS: [char; 8] = [' ', ':', '(', ')', '{', '}', '[', ']'
|
|||||||
|
|
||||||
impl Highlighter for DustHighlighter {
|
impl Highlighter for DustHighlighter {
|
||||||
fn highlight(&self, line: &str, _cursor: usize) -> reedline::StyledText {
|
fn highlight(&self, line: &str, _cursor: usize) -> reedline::StyledText {
|
||||||
fn highlight_identifier(styled: &mut StyledText, word: &str, map: &Map) -> bool {
|
let mut styled = StyledText::new();
|
||||||
for (key, (value, _type)) in map.variables().unwrap().iter() {
|
|
||||||
|
for word in line.split_inclusive(&HIGHLIGHT_TERMINATORS) {
|
||||||
|
let mut word_is_highlighted = false;
|
||||||
|
|
||||||
|
for key in self.context.inner().unwrap().keys() {
|
||||||
if key == &word {
|
if key == &word {
|
||||||
styled.push((Style::new().bold(), word.to_string()));
|
styled.push((Style::new().bold(), word.to_string()));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Value::Map(nested_map) = value {
|
word_is_highlighted = true;
|
||||||
return highlight_identifier(styled, word, nested_map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for built_in_value in built_in_values() {
|
for built_in_value in built_in_values() {
|
||||||
if built_in_value.name() == word {
|
if built_in_value.name() == word {
|
||||||
styled.push((Style::new().bold(), word.to_string()));
|
styled.push((Style::new().bold(), word.to_string()));
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
word_is_highlighted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut styled = StyledText::new();
|
|
||||||
|
|
||||||
for word in line.split_inclusive(&HIGHLIGHT_TERMINATORS) {
|
|
||||||
let word_is_highlighted =
|
|
||||||
highlight_identifier(&mut styled, &word[0..word.len() - 1], &self.context);
|
|
||||||
|
|
||||||
if word_is_highlighted {
|
if word_is_highlighted {
|
||||||
let final_char = word.chars().last().unwrap();
|
let final_char = word.chars().last().unwrap();
|
||||||
|
|
||||||
@ -239,11 +230,11 @@ impl Prompt for StarshipPrompt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct DustCompleter {
|
pub struct DustCompleter {
|
||||||
context: Map,
|
context: Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DustCompleter {
|
impl DustCompleter {
|
||||||
fn new(context: Map) -> Self {
|
fn new(context: Context) -> Self {
|
||||||
DustCompleter { context }
|
DustCompleter { context }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,7 +293,7 @@ impl Completer for DustCompleter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Value::Map(map) = built_in_value.get() {
|
if let Value::Map(map) = built_in_value.get() {
|
||||||
for (key, (value, _type)) in map.variables().unwrap().iter() {
|
for (key, value) in map.iter() {
|
||||||
if key.contains(last_word) {
|
if key.contains(last_word) {
|
||||||
suggestions.push(Suggestion {
|
suggestions.push(Suggestion {
|
||||||
value: format!("{name}:{key}"),
|
value: format!("{name}:{key}"),
|
||||||
@ -316,7 +307,12 @@ impl Completer for DustCompleter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, (value, _type)) in self.context.variables().unwrap().iter() {
|
for (key, value_data) in self.context.inner().unwrap().iter() {
|
||||||
|
let value = match value_data {
|
||||||
|
ValueData::Value { inner, .. } => inner,
|
||||||
|
ValueData::ExpectedType { .. } => continue,
|
||||||
|
};
|
||||||
|
|
||||||
if key.contains(last_word) {
|
if key.contains(last_word) {
|
||||||
suggestions.push(Suggestion {
|
suggestions.push(Suggestion {
|
||||||
value: key.to_string(),
|
value: key.to_string(),
|
||||||
@ -332,7 +328,7 @@ impl Completer for DustCompleter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_shell(context: Map) -> Result<(), Error> {
|
fn run_shell(context: Context) -> Result<(), Error> {
|
||||||
let mut interpreter = Interpreter::new(context.clone());
|
let mut interpreter = Interpreter::new(context.clone());
|
||||||
let mut keybindings = default_emacs_keybindings();
|
let mut keybindings = default_emacs_keybindings();
|
||||||
|
|
||||||
|
197
src/value/map.rs
197
src/value/map.rs
@ -1,136 +1,73 @@
|
|||||||
use serde::{
|
use serde::{Deserialize, Serialize};
|
||||||
de::{MapAccess, Visitor},
|
|
||||||
ser::SerializeMap,
|
|
||||||
Deserialize, Serialize,
|
|
||||||
};
|
|
||||||
use stanza::{
|
use stanza::{
|
||||||
renderer::{console::Console, Renderer},
|
renderer::{console::Console, Renderer},
|
||||||
style::{HAlign, Styles},
|
style::{HAlign, Styles},
|
||||||
table::{Row, Table},
|
table::{Row, Table},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
marker::PhantomData,
|
|
||||||
sync::{Arc, RwLock, RwLockReadGuard},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{error::rw_lock_error::RwLockError, value::Value, Structure, Type};
|
use crate::value::Value;
|
||||||
|
|
||||||
/// A collection dust variables comprised of key-value pairs.
|
/// A collection dust variables comprised of key-value pairs.
|
||||||
///
|
///
|
||||||
/// The inner value is a BTreeMap in order to allow VariableMap instances to be sorted and compared
|
/// The inner value is a BTreeMap in order to allow VariableMap instances to be sorted and compared
|
||||||
/// to one another.
|
/// to one another.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
variables: Arc<RwLock<BTreeMap<String, (Value, Type)>>>,
|
inner: BTreeMap<String, Value>,
|
||||||
structure: Option<Structure>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
/// Creates a new instace.
|
/// Creates a new instace.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Map {
|
Map {
|
||||||
variables: Arc::new(RwLock::new(BTreeMap::new())),
|
inner: BTreeMap::new(),
|
||||||
structure: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_structure(structure: Structure) -> Self {
|
pub fn with_values(variables: BTreeMap<String, Value>) -> Self {
|
||||||
let mut variables = BTreeMap::new();
|
Map { inner: variables }
|
||||||
|
|
||||||
for (key, (value_option, r#type)) in structure.inner() {
|
|
||||||
variables.insert(
|
|
||||||
key.clone(),
|
|
||||||
(
|
|
||||||
value_option.clone().unwrap_or(Value::none()),
|
|
||||||
r#type.clone(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map {
|
pub fn len(&self) -> usize {
|
||||||
variables: Arc::new(RwLock::new(variables)),
|
self.inner.len()
|
||||||
structure: Some(structure),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_variables(variables: BTreeMap<String, (Value, Type)>) -> Self {
|
pub fn iter(&self) -> impl Iterator<Item = (&String, &Value)> {
|
||||||
Map {
|
self.inner.iter()
|
||||||
variables: Arc::new(RwLock::new(variables)),
|
|
||||||
structure: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_from(other: &Self) -> Result<Self, RwLockError> {
|
pub fn get(&self, key: &str) -> Option<&Value> {
|
||||||
let mut new_map = BTreeMap::new();
|
self.inner.get(key)
|
||||||
|
|
||||||
for (key, (value, r#type)) in other.variables()?.iter() {
|
|
||||||
new_map.insert(key.clone(), (value.clone(), r#type.clone()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Map {
|
pub fn set(&mut self, key: String, value: Value) {
|
||||||
variables: Arc::new(RwLock::new(new_map)),
|
self.inner.insert(key, value);
|
||||||
structure: other.structure.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn variables(
|
|
||||||
&self,
|
|
||||||
) -> Result<RwLockReadGuard<BTreeMap<String, (Value, Type)>>, RwLockError> {
|
|
||||||
self.variables.read().map_err(|_| RwLockError)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&self, key: String, value: Value) -> Result<Option<(Value, Type)>, RwLockError> {
|
|
||||||
log::info!("Setting variable {key} = {value}");
|
|
||||||
|
|
||||||
let value_type = value.r#type();
|
|
||||||
let previous = self
|
|
||||||
.variables
|
|
||||||
.write()?
|
|
||||||
.insert(key, (value, value_type.clone()));
|
|
||||||
|
|
||||||
Ok(previous)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_type(
|
|
||||||
&self,
|
|
||||||
key: String,
|
|
||||||
r#type: Type,
|
|
||||||
) -> Result<Option<(Value, Type)>, RwLockError> {
|
|
||||||
log::info!("Setting type {key} = {}", r#type);
|
|
||||||
|
|
||||||
let previous = self
|
|
||||||
.variables
|
|
||||||
.write()
|
|
||||||
.map_err(|_| RwLockError)?
|
|
||||||
.insert(key, (Value::none(), r#type));
|
|
||||||
|
|
||||||
Ok(previous)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_text_table(&self) -> Table {
|
pub fn as_text_table(&self) -> Table {
|
||||||
let variables = self.variables.read().unwrap().clone().into_iter();
|
|
||||||
let mut table = Table::with_styles(Styles::default().with(HAlign::Centred));
|
let mut table = Table::with_styles(Styles::default().with(HAlign::Centred));
|
||||||
|
|
||||||
for (key, (value, r#type)) in variables {
|
for (key, value) in &self.inner {
|
||||||
if let Value::Map(map) = value {
|
if let Value::Map(map) = value {
|
||||||
table.push_row(Row::new(
|
|
||||||
Styles::default(),
|
|
||||||
vec![key.into(), map.as_text_table().into(), "".into()],
|
|
||||||
));
|
|
||||||
} else if let Value::List(list) = value {
|
|
||||||
table.push_row(Row::new(
|
table.push_row(Row::new(
|
||||||
Styles::default(),
|
Styles::default(),
|
||||||
vec![
|
vec![
|
||||||
key.into(),
|
key.into(),
|
||||||
list.as_text_table().into(),
|
map.as_text_table().into(),
|
||||||
r#type.to_string().into(),
|
"".to_string().into(),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
} else if let Value::List(list) = value {
|
||||||
|
table.push_row(Row::new(
|
||||||
|
Styles::default(),
|
||||||
|
vec![key.into(), list.as_text_table().into()],
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
table.push_row([key, value.to_string(), r#type.to_string()]);
|
table.push_row([key, &value.to_string()]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,32 +85,6 @@ impl Default for Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for Map {}
|
|
||||||
|
|
||||||
impl PartialEq for Map {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
let left = self.variables.read().unwrap().clone().into_iter();
|
|
||||||
let right = other.variables.read().unwrap().clone().into_iter();
|
|
||||||
|
|
||||||
left.eq(right)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for Map {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
let left = self.variables.read().unwrap().clone().into_iter();
|
|
||||||
let right = other.variables.read().unwrap().clone().into_iter();
|
|
||||||
|
|
||||||
left.cmp(right)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Map {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Map {
|
impl Display for Map {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
let renderer = Console::default();
|
let renderer = Console::default();
|
||||||
@ -181,63 +92,3 @@ impl Display for Map {
|
|||||||
f.write_str(&renderer.render(&self.as_text_table()))
|
f.write_str(&renderer.render(&self.as_text_table()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Map {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
let variables = self.variables.read().unwrap();
|
|
||||||
let mut map = serializer.serialize_map(Some(variables.len()))?;
|
|
||||||
|
|
||||||
for (key, (value, _type)) in variables.iter() {
|
|
||||||
map.serialize_entry(key, value)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
map.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MapVisitor {
|
|
||||||
marker: PhantomData<fn() -> Map>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MapVisitor {
|
|
||||||
fn new() -> Self {
|
|
||||||
MapVisitor {
|
|
||||||
marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for MapVisitor {
|
|
||||||
type Value = Map;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
|
||||||
formatter.write_str("key-value pairs")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_map<M>(self, mut access: M) -> std::result::Result<Map, M::Error>
|
|
||||||
where
|
|
||||||
M: MapAccess<'de>,
|
|
||||||
{
|
|
||||||
let map = Map::new();
|
|
||||||
|
|
||||||
{
|
|
||||||
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
|
||||||
map.set(key, value).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(map)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Map {
|
|
||||||
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
deserializer.deserialize_any(MapVisitor::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -82,7 +82,7 @@ impl Value {
|
|||||||
Value::Map(map) => {
|
Value::Map(map) => {
|
||||||
let mut identifier_types = Vec::new();
|
let mut identifier_types = Vec::new();
|
||||||
|
|
||||||
for (key, (value, _)) in map.variables().unwrap().iter() {
|
for (key, value) in map.iter() {
|
||||||
identifier_types.push((
|
identifier_types.push((
|
||||||
Identifier::new(key.clone()),
|
Identifier::new(key.clone()),
|
||||||
TypeSpecification::new(value.r#type()),
|
TypeSpecification::new(value.r#type()),
|
||||||
@ -858,10 +858,10 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||||||
where
|
where
|
||||||
M: MapAccess<'de>,
|
M: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
||||||
map.set(key, value).unwrap();
|
map.set(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Map(map))
|
Ok(Value::Map(map))
|
||||||
|
@ -92,10 +92,10 @@ fn modify_map() {
|
|||||||
",
|
",
|
||||||
);
|
);
|
||||||
|
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
map.set("x".to_string(), Value::Integer(1)).unwrap();
|
map.set("x".to_string(), Value::Integer(1));
|
||||||
map.set("y".to_string(), Value::Integer(2)).unwrap();
|
map.set("y".to_string(), Value::Integer(2));
|
||||||
|
|
||||||
assert_eq!(Ok(Value::Map(map)), result);
|
assert_eq!(Ok(Value::Map(map)), result);
|
||||||
}
|
}
|
||||||
@ -137,10 +137,10 @@ fn modify_map_values() {
|
|||||||
",
|
",
|
||||||
);
|
);
|
||||||
|
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
map.set("x".to_string(), Value::Integer(1)).unwrap();
|
map.set("x".to_string(), Value::Integer(1));
|
||||||
map.set("y".to_string(), Value::Integer(2)).unwrap();
|
map.set("y".to_string(), Value::Integer(2));
|
||||||
|
|
||||||
assert_eq!(Ok(Value::Map(map)), result);
|
assert_eq!(Ok(Value::Map(map)), result);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use dust_lang::*;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn format_simple_program() {
|
fn format_simple_program() {
|
||||||
let mut interpreter = Interpreter::new(Map::new());
|
let mut interpreter = Interpreter::new(Context::new());
|
||||||
|
|
||||||
assert_eq!(interpreter.format("x=1"), Ok("x = 1\n".to_string()));
|
assert_eq!(interpreter.format("x=1"), Ok("x = 1\n".to_string()));
|
||||||
}
|
}
|
||||||
@ -16,7 +16,7 @@ const FORMATTED_BLOCK: &str = "{
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn format_block() {
|
fn format_block() {
|
||||||
let mut interpreter = Interpreter::new(Map::new());
|
let mut interpreter = Interpreter::new(Context::new());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpreter.format("{1 2 3}"),
|
interpreter.format("{1 2 3}"),
|
||||||
@ -34,7 +34,7 @@ const FORMATTED_MAP: &str = "{
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn format_map() {
|
fn format_map() {
|
||||||
let mut interpreter = Interpreter::new(Map::new());
|
let mut interpreter = Interpreter::new(Context::new());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpreter.format("{{x=1 y <int> = 2}}"),
|
interpreter.format("{{x=1 y <int> = 2}}"),
|
||||||
@ -49,7 +49,7 @@ const FORMATTED_FUNCTION: &str = "(x <int>) <num> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn format_function() {
|
fn format_function() {
|
||||||
let mut interpreter = Interpreter::new(Map::new());
|
let mut interpreter = Interpreter::new(Context::new());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpreter.format("( x< int > )<num>{x/2}"),
|
interpreter.format("( x< int > )<num>{x/2}"),
|
||||||
Ok(FORMATTED_FUNCTION.to_string())
|
Ok(FORMATTED_FUNCTION.to_string())
|
||||||
|
@ -89,9 +89,9 @@ fn function_context_captures_functions() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn function_context_captures_structure_definitions() {
|
fn function_context_captures_structure_definitions() {
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
map.set("name".to_string(), Value::string("bob")).unwrap();
|
map.set("name".to_string(), Value::string("bob"));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret(
|
interpret(
|
||||||
|
@ -17,7 +17,7 @@ fn simple_structure() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new_structure() {
|
fn new_structure() {
|
||||||
let result = interpret(
|
let _result = interpret(
|
||||||
"
|
"
|
||||||
Coords = struct {
|
Coords = struct {
|
||||||
x <float> = 0.0
|
x <float> = 0.0
|
||||||
@ -35,7 +35,9 @@ fn new_structure() {
|
|||||||
|
|
||||||
map.insert("x".to_string(), (Some(Value::Integer(0)), Type::Integer));
|
map.insert("x".to_string(), (Some(Value::Integer(0)), Type::Integer));
|
||||||
|
|
||||||
let expected = Value::Map(Map::from_structure(Structure::new(map)));
|
// let expected = Value::Map(Map::from_structure(Structure::new(map)));
|
||||||
|
|
||||||
assert_eq!(Ok(expected), result);
|
// assert_eq!(Ok(expected), result);
|
||||||
|
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
@ -69,11 +69,10 @@ fn empty_list() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn map() {
|
fn map() {
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
map.set("x".to_string(), Value::Integer(1)).unwrap();
|
map.set("x".to_string(), Value::Integer(1));
|
||||||
map.set("foo".to_string(), Value::string("bar".to_string()))
|
map.set("foo".to_string(), Value::string("bar".to_string()));
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
|
assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
|
||||||
}
|
}
|
||||||
@ -85,11 +84,10 @@ fn empty_map() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn map_types() {
|
fn map_types() {
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
map.set("x".to_string(), Value::Integer(1)).unwrap();
|
map.set("x".to_string(), Value::Integer(1));
|
||||||
map.set("foo".to_string(), Value::string("bar".to_string()))
|
map.set("foo".to_string(), Value::string("bar".to_string()));
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret("{ x <int> = 1, foo <str> = 'bar' }"),
|
interpret("{ x <int> = 1, foo <str> = 'bar' }"),
|
||||||
|
Loading…
Reference in New Issue
Block a user