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 {
|
if i <= 1 {
|
||||||
1
|
1
|
||||||
} else {
|
} 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> {
|
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)?;
|
||||||
|
@ -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(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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();
|
||||||
|
@ -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(),
|
||||||
|
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.
|
/// 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}.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
51
src/main.rs
51
src/main.rs
@ -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.");
|
||||||
|
@ -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 {
|
||||||
|
@ -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>
|
||||||
|
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