Implement assignment
This commit is contained in:
parent
1f829d930a
commit
b476818ba3
@ -15,6 +15,7 @@ pub enum Error {
|
|||||||
UnexpectedSourceNode {
|
UnexpectedSourceNode {
|
||||||
expected: &'static str,
|
expected: &'static str,
|
||||||
actual: &'static str,
|
actual: &'static str,
|
||||||
|
location: tree_sitter::Point,
|
||||||
},
|
},
|
||||||
|
|
||||||
ExpectedFieldName,
|
ExpectedFieldName,
|
||||||
@ -552,7 +553,7 @@ impl fmt::Display for Error {
|
|||||||
macro_info.identifier,
|
macro_info.identifier,
|
||||||
macro_info.inputs
|
macro_info.inputs
|
||||||
),
|
),
|
||||||
UnexpectedSourceNode { expected, actual } => write!(f, "Unexpected source node. Expected {expected}, but found {actual}."),
|
UnexpectedSourceNode { expected, actual, location } => write!(f, "Unexpected syntax at {location}. Expected {expected}, but found {actual}."),
|
||||||
ExpectedFieldName => write!(f, "Expected a field name for this node, but none was found."),
|
ExpectedFieldName => write!(f, "Expected a field name for this node, but none was found."),
|
||||||
WrongTypeCombination { expected, actual } => write!(f, "Wrong type combination. Expected {expected}, found {actual}."),
|
WrongTypeCombination { expected, actual } => write!(f, "Wrong type combination. Expected {expected}, found {actual}."),
|
||||||
ExpectedChildNode { empty_node_sexp } => write!(f, "Expected this node to have a child, {empty_node_sexp}."),
|
ExpectedChildNode { empty_node_sexp } => write!(f, "Expected this node to have a child, {empty_node_sexp}."),
|
||||||
|
127
src/interface.rs
127
src/interface.rs
@ -72,10 +72,10 @@ trait EvaluatorTree: Sized {
|
|||||||
///
|
///
|
||||||
/// The Evaluator turns a tree sitter concrete syntax tree into a vector of
|
/// The Evaluator turns a tree sitter concrete syntax tree into a vector of
|
||||||
/// abstract trees called [Item][]s that can be run to execute the source code.
|
/// abstract trees called [Item][]s that can be run to execute the source code.
|
||||||
pub struct Evaluator<'context, 'source> {
|
pub struct Evaluator<'context, 'code> {
|
||||||
_parser: Parser,
|
_parser: Parser,
|
||||||
context: &'context mut VariableMap,
|
context: &'context mut VariableMap,
|
||||||
source: &'source str,
|
source: &'code str,
|
||||||
tree: TSTree,
|
tree: TSTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,8 +85,8 @@ impl Debug for Evaluator<'_, '_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'c, 's> Evaluator<'c, 's> {
|
impl<'context, 'code> Evaluator<'context, 'code> {
|
||||||
fn new(mut parser: Parser, context: &'c mut VariableMap, source: &'s str) -> Self {
|
fn new(mut parser: Parser, context: &'context mut VariableMap, source: &'code str) -> Self {
|
||||||
let tree = parser.parse(source, None).unwrap();
|
let tree = parser.parse(source, None).unwrap();
|
||||||
|
|
||||||
Evaluator {
|
Evaluator {
|
||||||
@ -104,8 +104,9 @@ impl<'c, 's> Evaluator<'c, 's> {
|
|||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
|
|
||||||
for (index, node) in root_node.children(&mut cursor).enumerate() {
|
for (index, node) in root_node.children(&mut cursor).enumerate() {
|
||||||
if let Ok(item) = Item::new(node, self.source) {
|
match Item::new(node, self.source) {
|
||||||
items.push(item);
|
Ok(item) => items.push(item),
|
||||||
|
Err(error) => results.push(Err(error)),
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{node:?}");
|
println!("{node:?}");
|
||||||
@ -118,7 +119,7 @@ impl<'c, 's> Evaluator<'c, 's> {
|
|||||||
|
|
||||||
for item in &items {
|
for item in &items {
|
||||||
match item {
|
match item {
|
||||||
Item::Comment(comment) => results.push(Ok(Value::String(comment.clone()))),
|
Item::Comment(comment) => results.push(Ok(Value::String(comment.to_string()))),
|
||||||
Item::Statement(statement) => {
|
Item::Statement(statement) => {
|
||||||
results.push(statement.run(self.context, &mut cursor, self.source))
|
results.push(statement.run(self.context, &mut cursor, self.source))
|
||||||
}
|
}
|
||||||
@ -146,6 +147,7 @@ impl Item {
|
|||||||
return Err(Error::UnexpectedSourceNode {
|
return Err(Error::UnexpectedSourceNode {
|
||||||
expected: "item",
|
expected: "item",
|
||||||
actual: node.kind(),
|
actual: node.kind(),
|
||||||
|
location: node.start_position(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,9 +155,9 @@ impl Item {
|
|||||||
|
|
||||||
if child.kind() == "comment" {
|
if child.kind() == "comment" {
|
||||||
let byte_range = node.byte_range();
|
let byte_range = node.byte_range();
|
||||||
let value_string = &source[byte_range];
|
let comment_text = &source[byte_range];
|
||||||
|
|
||||||
Ok(Item::Comment(value_string.to_string()))
|
Ok(Item::Comment(comment_text.to_string()))
|
||||||
} else if child.kind() == "statement" {
|
} else if child.kind() == "statement" {
|
||||||
let child = node.child(0).unwrap();
|
let child = node.child(0).unwrap();
|
||||||
Ok(Item::Statement(Statement::new(child, source)?))
|
Ok(Item::Statement(Statement::new(child, source)?))
|
||||||
@ -163,6 +165,7 @@ impl Item {
|
|||||||
Err(Error::UnexpectedSourceNode {
|
Err(Error::UnexpectedSourceNode {
|
||||||
expected: "comment or statement",
|
expected: "comment or statement",
|
||||||
actual: node.kind(),
|
actual: node.kind(),
|
||||||
|
location: node.start_position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +178,7 @@ impl Item {
|
|||||||
/// referencing variables.
|
/// referencing variables.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Open(Expression),
|
Expression(Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
@ -185,13 +188,15 @@ impl Statement {
|
|||||||
} else {
|
} else {
|
||||||
node
|
node
|
||||||
};
|
};
|
||||||
|
|
||||||
let child = node.child(0).unwrap();
|
let child = node.child(0).unwrap();
|
||||||
|
|
||||||
match node.kind() {
|
match node.kind() {
|
||||||
"open_statement" => Ok(Self::Open(Expression::new(child, source)?)),
|
"expression" => Ok(Self::Expression(Expression::new(child, source)?)),
|
||||||
_ => Err(Error::UnexpectedSourceNode {
|
_ => Err(Error::UnexpectedSourceNode {
|
||||||
expected: "open_statement",
|
expected: "expression",
|
||||||
actual: node.kind(),
|
actual: node.kind(),
|
||||||
|
location: node.start_position(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +208,7 @@ impl Statement {
|
|||||||
source: &str,
|
source: &str,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Open(expression) => expression.run(context, &mut cursor, source),
|
Statement::Expression(expression) => expression.run(context, &mut cursor, source),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,8 +217,31 @@ impl Statement {
|
|||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
Value(Value),
|
Value(Value),
|
||||||
Operation(Box<Operation>),
|
|
||||||
ControlFlow(Box<ControlFlow>),
|
ControlFlow(Box<ControlFlow>),
|
||||||
|
Assignment(Box<Assignment>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub struct Assignment {
|
||||||
|
identifier: String,
|
||||||
|
statement: Statement,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Assignment {
|
||||||
|
pub fn new(node: Node, source: &str) -> Result<Self> {
|
||||||
|
let sexp = node.to_sexp();
|
||||||
|
println!("{sexp}");
|
||||||
|
|
||||||
|
let identifier_node = node.child(0).unwrap();
|
||||||
|
let statement_node = node.child(2).unwrap();
|
||||||
|
let identifier = source[identifier_node.byte_range()].to_string();
|
||||||
|
let statement = Statement::new(statement_node, source)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
identifier,
|
||||||
|
statement,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
@ -231,18 +259,19 @@ impl Expression {
|
|||||||
Ok(Self::Identifier(identifier.to_string()))
|
Ok(Self::Identifier(identifier.to_string()))
|
||||||
} else if node.kind() == "value" {
|
} else if node.kind() == "value" {
|
||||||
Ok(Expression::Value(Value::new(node, source)?))
|
Ok(Expression::Value(Value::new(node, source)?))
|
||||||
} else if node.kind() == "operation" {
|
|
||||||
Ok(Expression::Operation(Box::new(Operation::new(
|
|
||||||
node, source,
|
|
||||||
)?)))
|
|
||||||
} else if node.kind() == "control_flow" {
|
} else if node.kind() == "control_flow" {
|
||||||
Ok(Expression::ControlFlow(Box::new(ControlFlow::new(
|
Ok(Expression::ControlFlow(Box::new(ControlFlow::new(
|
||||||
node, source,
|
node, source,
|
||||||
)?)))
|
)?)))
|
||||||
|
} else if node.kind() == "assignment" {
|
||||||
|
Ok(Expression::Assignment(Box::new(Assignment::new(
|
||||||
|
node, source,
|
||||||
|
)?)))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnexpectedSourceNode {
|
Err(Error::UnexpectedSourceNode {
|
||||||
expected: "identifier, operation, control_flow or value",
|
expected: "identifier, operation, control_flow, assignment or value",
|
||||||
actual: node.kind(),
|
actual: node.kind(),
|
||||||
|
location: node.start_position(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,64 +293,12 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Value(value) => Ok(value.clone()),
|
Expression::Value(value) => Ok(value.clone()),
|
||||||
Expression::Operation(operation) => operation.run(context, &mut cursor, source),
|
|
||||||
Expression::ControlFlow(control_flow) => control_flow.run(context, &mut cursor, source),
|
Expression::ControlFlow(control_flow) => control_flow.run(context, &mut cursor, source),
|
||||||
|
Expression::Assignment(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
|
||||||
pub struct Operation {
|
|
||||||
left: Expression,
|
|
||||||
operator: String,
|
|
||||||
right: Expression,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Operation {
|
|
||||||
fn new(node: Node, source: &str) -> Result<Self> {
|
|
||||||
let first_child = node.child(0).unwrap();
|
|
||||||
let second_child = node.child(1).unwrap();
|
|
||||||
let third_child = node.child(2).unwrap();
|
|
||||||
let left = Expression::new(first_child, source)?;
|
|
||||||
let operator = second_child.child(0).unwrap().kind().to_string();
|
|
||||||
let right = Expression::new(third_child, source)?;
|
|
||||||
|
|
||||||
Ok(Operation {
|
|
||||||
left,
|
|
||||||
operator,
|
|
||||||
right,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
context: &mut VariableMap,
|
|
||||||
mut cursor: &mut TreeCursor,
|
|
||||||
source: &str,
|
|
||||||
) -> Result<Value> {
|
|
||||||
let left = self.left.run(context, &mut cursor, source)?;
|
|
||||||
let right = self.right.run(context, &mut cursor, source)?;
|
|
||||||
|
|
||||||
match self.operator.as_str() {
|
|
||||||
"+" => left + right,
|
|
||||||
"-" => left - right,
|
|
||||||
"=" => {
|
|
||||||
if let Expression::Identifier(key) = &self.left {
|
|
||||||
context.set_value(key, right)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Value::Empty)
|
|
||||||
}
|
|
||||||
"==" => Ok(Value::Boolean(left == right)),
|
|
||||||
_ => Err(Error::CustomMessage("Operator not supported.".to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Respresentation of an if-then-else logic gate.
|
|
||||||
///
|
|
||||||
/// A ControlFlow instance represents work to be done when the "run" method is
|
|
||||||
/// called.
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct ControlFlow {
|
pub struct ControlFlow {
|
||||||
if_expression: Expression,
|
if_expression: Expression,
|
||||||
@ -377,9 +354,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn evaluate_empty() {
|
fn evaluate_empty() {
|
||||||
assert_eq!(eval("()"), vec![Ok(Value::Empty)]);
|
assert_eq!(eval(""), vec![]);
|
||||||
assert_eq!(eval("x = 9 ()"), vec![Ok(Value::Empty)]);
|
assert_eq!(eval("x = 9"), vec![]);
|
||||||
assert_eq!(eval("y = 'foobar' ()"), vec![Ok(Value::Empty)]);
|
assert_eq!(eval("'foo' + 'bar'"), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -187,6 +187,7 @@ impl Value {
|
|||||||
_ => Err(Error::UnexpectedSourceNode {
|
_ => Err(Error::UnexpectedSourceNode {
|
||||||
expected: "integer, string, boolean, float, list or empty",
|
expected: "integer, string, boolean, float, list or empty",
|
||||||
actual: node.kind(),
|
actual: node.kind(),
|
||||||
|
location: node.start_position(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user