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 {
1
} 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> {
let expression_run = self.collection.run(source, context)?;
let values = expression_run.as_list()?.items();
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 {
values.par_iter().try_for_each(|value| {
let iter_context = Map::clone_from(context)?;

View File

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

View File

@ -26,12 +26,14 @@ impl FunctionNode {
r#type: Type,
syntax_position: SyntaxPosition,
) -> Self {
Self {
let context = Map::new();
FunctionNode {
parameters,
body,
r#type,
syntax_position,
context: Map::new(),
context,
}
}
@ -55,6 +57,10 @@ impl FunctionNode {
&self.syntax_position
}
pub fn context(&self) -> &Map {
&self.context
}
pub fn return_type(&self) -> &Type {
match &self.r#type {
Type::Function {
@ -122,12 +128,6 @@ impl AbstractTree for FunctionNode {
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()) {
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> {
Ok(Value::Function(Function::ContextDefined(Arc::new(
self.clone(),
))))
let self_as_value = Value::Function(Function::ContextDefined(Arc::new(self.clone())));
Ok(self_as_value)
}
fn expected_type(&self, _context: &Map) -> Result<Type> {

View File

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

View File

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

View File

@ -160,9 +160,6 @@ pub enum Error {
/// Failed to find a variable with a value for this key.
VariableIdentifierNotFound(String),
/// Failed to find a variable with a function value for this key.
FunctionIdentifierNotFound(String),
/// The function failed due to an external error.
External(String),
@ -179,6 +176,9 @@ pub enum Error {
SerdeJson(String),
ParserCancelled,
ExpectedIterable {
actual: Value,
},
}
impl Error {
@ -391,14 +391,7 @@ impl fmt::Display for Error {
"Expected a string, list, map or table, but got {actual}.",
)
}
VariableIdentifierNotFound(key) => write!(
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}."
),
VariableIdentifierNotFound(key) => write!(f, "Variable {key} does not exist.",),
UnexpectedSyntaxNode {
expected,
actual,
@ -449,6 +442,9 @@ impl fmt::Display for Error {
"Parsing was cancelled either manually or because it took too long."
),
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,
/// Output a concrete syntax tree of the input.
Syntax,
Syntax { path: String },
}
fn main() {
@ -87,7 +87,9 @@ fn main() {
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();
println!("{}", interpreter.syntax_tree().unwrap());
@ -96,6 +98,8 @@ fn main() {
}
if let Some(CliCommand::Format) = args.cli_command {
interpreter.parse(&source).unwrap();
println!("{}", interpreter.format());
return;
@ -251,18 +255,32 @@ impl Completer for DustCompleter {
let last_word = if let Some(word) = line.rsplit([' ', ':']).next() {
word
} else {
""
line
};
if let Ok(path) = PathBuf::try_from(last_word) {
if let Ok(read_dir) = path.read_dir() {
for entry in read_dir {
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 {
value: entry.file_name().into_string().unwrap(),
description: None,
value: entry.path().to_string_lossy().to_string(),
description: Some(description.to_string()),
extra: None,
span: Span::new(pos, pos),
span: Span::new(pos - last_word.len(), pos),
append_whitespace: false,
});
}
@ -335,9 +353,12 @@ fn run_shell(context: Map) -> Result<()> {
ReedlineEvent::Edit(vec![EditCommand::InsertString(" ".to_string())]),
);
keybindings.add_binding(
KeyModifiers::CONTROL,
KeyCode::Char('h'),
ReedlineEvent::Menu("variable menu".to_string()),
KeyModifiers::NONE,
KeyCode::Tab,
ReedlineEvent::Multiple(vec![
ReedlineEvent::Menu("context menu".to_string()),
ReedlineEvent::MenuNext,
]),
);
let edit_mode = Box::new(Emacs::new(keybindings));
@ -357,8 +378,10 @@ fn run_shell(context: Map) -> Result<()> {
.with_completer(Box::new(completer))
.with_menu(ReedlineMenu::EngineCompleter(Box::new(
ColumnarMenu::default()
.with_name("variable menu")
.with_text_style(Style::new().fg(Color::White)),
.with_name("context menu")
.with_text_style(Style::new().fg(Color::White))
.with_columns(1)
.with_column_padding(10),
)));
let mut prompt = StarshipPrompt::new();
@ -369,8 +392,6 @@ fn run_shell(context: Map) -> Result<()> {
match sig {
Ok(Signal::Success(buffer)) => {
prompt.reload();
if buffer.trim().is_empty() {
continue;
}
@ -383,8 +404,10 @@ fn run_shell(context: Map) -> Result<()> {
println!("{value}")
}
}
Err(error) => println!("Error: {error}"),
Err(error) => println!("{error}"),
}
prompt.reload();
}
Ok(Signal::CtrlD) | Ok(Signal::CtrlC) => {
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 {

View File

@ -204,7 +204,7 @@ impl<'de> Visitor<'de> for MapVisitor {
type Value = Map;
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>

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))))))))))))))))))))))