Clean up
This commit is contained in:
parent
433306b3e1
commit
6a9ce76007
@ -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)
|
||||
|
@ -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)?;
|
||||
|
@ -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(),
|
||||
));
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -61,25 +61,33 @@ 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)
|
||||
};
|
||||
|
||||
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;
|
||||
let item = string.chars().nth(index).unwrap_or_default();
|
||||
|
@ -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(),
|
||||
|
18
src/error.rs
18
src/error.rs
@ -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}.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
51
src/main.rs
51
src/main.rs
@ -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.");
|
||||
|
@ -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 {
|
||||
|
@ -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>
|
||||
|
75
tree-sitter-dust/corpus/examples.txt
Normal file
75
tree-sitter-dust/corpus/examples.txt
Normal 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))))))))))))))))))))))
|
Loading…
Reference in New Issue
Block a user