1
0
This commit is contained in:
Jeff 2024-01-28 17:46:15 -05:00
parent 433306b3e1
commit 6a9ce76007
11 changed files with 192 additions and 53 deletions

View File

@ -1,9 +1,9 @@
fib = (i <int>) <int> { fib = (i <int>, fib <(int) -> int>) <int> {
if i <= 1 { if i <= 1 {
1 1
} else { } else {
self(i - 1) + self(i - 2) fib(i - 1) + fib(i - 2)
} }
} }
fib(8) fib(8, fib)

View File

@ -52,9 +52,38 @@ impl AbstractTree for For {
fn run(&self, source: &str, context: &Map) -> Result<Value> { fn run(&self, source: &str, context: &Map) -> Result<Value> {
let expression_run = self.collection.run(source, context)?; let expression_run = self.collection.run(source, context)?;
let values = expression_run.as_list()?.items();
let key = self.item_id.inner(); let key = self.item_id.inner();
if let Value::Range(range) = expression_run {
if self.is_async {
let mut iterable = Vec::with_capacity((range.end - range.start) as usize);
for i in range.start..range.end {
iterable.push(Value::Integer(i));
}
iterable.par_iter().try_for_each(|value| {
let iter_context = Map::clone_from(context)?;
iter_context.set(key.clone(), value.clone())?;
self.block.run(source, &iter_context).map(|_value| ())
})?;
} else {
let loop_context = Map::clone_from(context)?;
for i in range.start..range.end {
loop_context.set(key.clone(), Value::Integer(i))?;
self.block.run(source, &loop_context)?;
}
}
return Ok(Value::none());
}
let values = expression_run.as_list()?.items();
if self.is_async { if self.is_async {
values.par_iter().try_for_each(|value| { values.par_iter().try_for_each(|value| {
let iter_context = Map::clone_from(context)?; let iter_context = Map::clone_from(context)?;

View File

@ -96,7 +96,7 @@ impl AbstractTree for FunctionCall {
if let Some((value, _)) = variables.get(key) { if let Some((value, _)) = variables.get(key) {
value.clone() value.clone()
} else { } else {
return Err(Error::FunctionIdentifierNotFound( return Err(Error::VariableIdentifierNotFound(
identifier.inner().clone(), identifier.inner().clone(),
)); ));
} }

View File

@ -26,12 +26,14 @@ impl FunctionNode {
r#type: Type, r#type: Type,
syntax_position: SyntaxPosition, syntax_position: SyntaxPosition,
) -> Self { ) -> Self {
Self { let context = Map::new();
FunctionNode {
parameters, parameters,
body, body,
r#type, r#type,
syntax_position, syntax_position,
context: Map::new(), context,
} }
} }
@ -55,6 +57,10 @@ impl FunctionNode {
&self.syntax_position &self.syntax_position
} }
pub fn context(&self) -> &Map {
&self.context
}
pub fn return_type(&self) -> &Type { pub fn return_type(&self) -> &Type {
match &self.r#type { match &self.r#type {
Type::Function { Type::Function {
@ -122,12 +128,6 @@ impl AbstractTree for FunctionNode {
let function_context = Map::new(); let function_context = Map::new();
for (key, (_value, r#type)) in outer_context.variables()?.iter() {
if r#type.is_function() {
function_context.set_type(key.clone(), r#type.clone())?;
}
}
for (parameter, parameter_type) in parameters.iter().zip(parameter_types.iter()) { for (parameter, parameter_type) in parameters.iter().zip(parameter_types.iter()) {
function_context.set_type(parameter.inner().clone(), parameter_type.clone())?; function_context.set_type(parameter.inner().clone(), parameter_type.clone())?;
} }
@ -157,9 +157,9 @@ impl AbstractTree for FunctionNode {
} }
fn run(&self, _source: &str, _context: &Map) -> Result<Value> { fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
Ok(Value::Function(Function::ContextDefined(Arc::new( let self_as_value = Value::Function(Function::ContextDefined(Arc::new(self.clone())));
self.clone(),
)))) Ok(self_as_value)
} }
fn expected_type(&self, _context: &Map) -> Result<Type> { fn expected_type(&self, _context: &Map) -> Result<Type> {

View File

@ -61,25 +61,33 @@ impl AbstractTree for Index {
Ok(item) Ok(item)
} }
Value::Map(map) => { Value::Map(map) => {
let 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
map.variables()? .variables()?
.get(key) .get(key)
.map(|(value, _)| value.clone()) .map(|(value, _)| value.clone())
.unwrap_or_default() .unwrap_or_default();
} else {
let value = self.index.run(source, context)?;
let key = value.as_string()?;
map.variables()? (key.clone(), value)
} else {
let index_value = self.index.run(source, context)?;
let key = index_value.as_string()?;
let value = map
.variables()?
.get(key.as_str()) .get(key.as_str())
.map(|(value, _)| value.clone()) .map(|(value, _)| value.clone())
.unwrap_or_default() .unwrap_or_default();
(key.clone(), value)
}; };
if value.is_none() {
Err(Error::VariableIdentifierNotFound(key))
} else {
Ok(value) Ok(value)
} }
}
Value::String(string) => { Value::String(string) => {
let index = self.index.run(source, context)?.as_integer()? as usize; let index = self.index.run(source, context)?.as_integer()? as usize;
let item = string.chars().nth(index).unwrap_or_default(); let item = string.chars().nth(index).unwrap_or_default();

View File

@ -50,6 +50,7 @@ impl AbstractTree for ValueNode {
if current_node.is_named() { if current_node.is_named() {
let expression = Expression::from_syntax(current_node, source, context)?; let expression = Expression::from_syntax(current_node, source, context)?;
expressions.push(expression); expressions.push(expression);
} }
} }
@ -175,7 +176,7 @@ impl AbstractTree for ValueNode {
_ => { _ => {
return Err(Error::UnexpectedSyntaxNode { return Err(Error::UnexpectedSyntaxNode {
expected: expected:
"string, integer, float, boolean, range, list, map, option or structure" "string, integer, float, boolean, range, list, map, option, function or structure"
.to_string(), .to_string(),
actual: child.kind().to_string(), actual: child.kind().to_string(),
location: child.start_position(), location: child.start_position(),

View File

@ -160,9 +160,6 @@ pub enum Error {
/// Failed to find a variable with a value for this key. /// Failed to find a variable with a value for this key.
VariableIdentifierNotFound(String), VariableIdentifierNotFound(String),
/// Failed to find a variable with a function value for this key.
FunctionIdentifierNotFound(String),
/// The function failed due to an external error. /// The function failed due to an external error.
External(String), External(String),
@ -179,6 +176,9 @@ pub enum Error {
SerdeJson(String), SerdeJson(String),
ParserCancelled, ParserCancelled,
ExpectedIterable {
actual: Value,
},
} }
impl Error { impl Error {
@ -391,14 +391,7 @@ impl fmt::Display for Error {
"Expected a string, list, map or table, but got {actual}.", "Expected a string, list, map or table, but got {actual}.",
) )
} }
VariableIdentifierNotFound(key) => write!( VariableIdentifierNotFound(key) => write!(f, "Variable {key} does not exist.",),
f,
"Variable identifier is not bound to anything by context: {key}.",
),
FunctionIdentifierNotFound(key) => write!(
f,
"Function identifier is not bound to anything by context: {key}."
),
UnexpectedSyntaxNode { UnexpectedSyntaxNode {
expected, expected,
actual, actual,
@ -449,6 +442,9 @@ impl fmt::Display for Error {
"Parsing was cancelled either manually or because it took too long." "Parsing was cancelled either manually or because it took too long."
), ),
ExpectedFunctionType { actual } => write!(f, "Expected a function but got {actual}."), ExpectedFunctionType { actual } => write!(f, "Expected a function but got {actual}."),
ExpectedIterable { actual } => {
write!(f, "Expected an iterable value but got {actual}.")
}
} }
} }
} }

View File

@ -43,7 +43,7 @@ pub enum CliCommand {
Format, Format,
/// Output a concrete syntax tree of the input. /// Output a concrete syntax tree of the input.
Syntax, Syntax { path: String },
} }
fn main() { fn main() {
@ -87,7 +87,9 @@ fn main() {
let mut interpreter = Interpreter::new(context); let mut interpreter = Interpreter::new(context);
if let Some(CliCommand::Syntax) = args.cli_command { if let Some(CliCommand::Syntax { path }) = args.cli_command {
let source = read_to_string(path).unwrap();
interpreter.parse(&source).unwrap(); interpreter.parse(&source).unwrap();
println!("{}", interpreter.syntax_tree().unwrap()); println!("{}", interpreter.syntax_tree().unwrap());
@ -96,6 +98,8 @@ fn main() {
} }
if let Some(CliCommand::Format) = args.cli_command { if let Some(CliCommand::Format) = args.cli_command {
interpreter.parse(&source).unwrap();
println!("{}", interpreter.format()); println!("{}", interpreter.format());
return; return;
@ -251,18 +255,32 @@ impl Completer for DustCompleter {
let last_word = if let Some(word) = line.rsplit([' ', ':']).next() { let last_word = if let Some(word) = line.rsplit([' ', ':']).next() {
word word
} else { } else {
"" line
}; };
if let Ok(path) = PathBuf::try_from(last_word) { if let Ok(path) = PathBuf::try_from(last_word) {
if let Ok(read_dir) = path.read_dir() { if let Ok(read_dir) = path.read_dir() {
for entry in read_dir { for entry in read_dir {
if let Ok(entry) = entry { if let Ok(entry) = entry {
let description = if let Ok(file_type) = entry.file_type() {
if file_type.is_dir() {
"directory"
} else if file_type.is_file() {
"file"
} else if file_type.is_symlink() {
"symlink"
} else {
"unknown"
}
} else {
"unknown"
};
suggestions.push(Suggestion { suggestions.push(Suggestion {
value: entry.file_name().into_string().unwrap(), value: entry.path().to_string_lossy().to_string(),
description: None, description: Some(description.to_string()),
extra: None, extra: None,
span: Span::new(pos, pos), span: Span::new(pos - last_word.len(), pos),
append_whitespace: false, append_whitespace: false,
}); });
} }
@ -335,9 +353,12 @@ fn run_shell(context: Map) -> Result<()> {
ReedlineEvent::Edit(vec![EditCommand::InsertString(" ".to_string())]), ReedlineEvent::Edit(vec![EditCommand::InsertString(" ".to_string())]),
); );
keybindings.add_binding( keybindings.add_binding(
KeyModifiers::CONTROL, KeyModifiers::NONE,
KeyCode::Char('h'), KeyCode::Tab,
ReedlineEvent::Menu("variable menu".to_string()), ReedlineEvent::Multiple(vec![
ReedlineEvent::Menu("context menu".to_string()),
ReedlineEvent::MenuNext,
]),
); );
let edit_mode = Box::new(Emacs::new(keybindings)); let edit_mode = Box::new(Emacs::new(keybindings));
@ -357,8 +378,10 @@ fn run_shell(context: Map) -> Result<()> {
.with_completer(Box::new(completer)) .with_completer(Box::new(completer))
.with_menu(ReedlineMenu::EngineCompleter(Box::new( .with_menu(ReedlineMenu::EngineCompleter(Box::new(
ColumnarMenu::default() ColumnarMenu::default()
.with_name("variable menu") .with_name("context menu")
.with_text_style(Style::new().fg(Color::White)), .with_text_style(Style::new().fg(Color::White))
.with_columns(1)
.with_column_padding(10),
))); )));
let mut prompt = StarshipPrompt::new(); let mut prompt = StarshipPrompt::new();
@ -369,8 +392,6 @@ fn run_shell(context: Map) -> Result<()> {
match sig { match sig {
Ok(Signal::Success(buffer)) => { Ok(Signal::Success(buffer)) => {
prompt.reload();
if buffer.trim().is_empty() { if buffer.trim().is_empty() {
continue; continue;
} }
@ -383,8 +404,10 @@ fn run_shell(context: Map) -> Result<()> {
println!("{value}") println!("{value}")
} }
} }
Err(error) => println!("Error: {error}"), Err(error) => println!("{error}"),
} }
prompt.reload();
} }
Ok(Signal::CtrlD) | Ok(Signal::CtrlC) => { Ok(Signal::CtrlD) | Ok(Signal::CtrlC) => {
println!("\nLeaving the Dust shell."); println!("\nLeaving the Dust shell.");

View File

@ -35,6 +35,13 @@ impl Function {
} }
} }
} }
pub fn set(&self, key: String, value: Value) -> Result<Option<(Value, Type)>> {
match self {
Function::BuiltIn(_) => todo!(),
Function::ContextDefined(function_node) => function_node.set(key, value),
}
}
} }
impl Format for Function { impl Format for Function {

View File

@ -204,7 +204,7 @@ impl<'de> Visitor<'de> for MapVisitor {
type Value = Map; type Value = Map;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("Any valid whale data.") formatter.write_str("key-value pairs")
} }
fn visit_map<M>(self, mut access: M) -> std::result::Result<Map, M::Error> fn visit_map<M>(self, mut access: M) -> std::result::Result<Map, M::Error>

View File

@ -0,0 +1,75 @@
================================================================================
Fibonacci
================================================================================
fib = (i <int>) <int> {
if i <= 1 {
1
} else {
self(i - 1) + self(i - 2)
}
}
--------------------------------------------------------------------------------
(root
(statement
(assignment
(identifier)
(assignment_operator)
(statement
(expression
(value
(function
(identifier)
(type_specification
(type))
(type_specification
(type))
(block
(statement
(if_else
(if
(expression
(logic
(expression
(identifier))
(logic_operator)
(expression
(value
(integer)))))
(block
(statement
(expression
(value
(integer))))))
(else
(block
(statement
(expression
(math
(expression
(function_call
(function_expression
(identifier))
(expression
(math
(expression
(identifier))
(math_operator)
(expression
(value
(integer)))))))
(math_operator)
(expression
(function_call
(function_expression
(identifier))
(expression
(math
(expression
(identifier))
(math_operator)
(expression
(value
(integer))))))))))))))))))))))