Add example; Implement AST
This commit is contained in:
parent
4907dd9f8f
commit
8250d3cb8e
15
examples/clue_solver.ds
Normal file
15
examples/clue_solver.ds
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
suspects = ("White", "Green");
|
||||||
|
rooms = ("Library", "Kitchen");
|
||||||
|
weapons = ("Rope", "Lead Pipe");
|
||||||
|
|
||||||
|
make_guess = {
|
||||||
|
current_room = input.0;
|
||||||
|
|
||||||
|
if length(suspects) == 1
|
||||||
|
&& length(rooms) == 1
|
||||||
|
&& length(weapons) == 1
|
||||||
|
then
|
||||||
|
output 'It was ' + suspects.0 + ' in the ' + rooms.0 + ' with the ' + weapons.0 '!';
|
||||||
|
else
|
||||||
|
output 'I accuse ' + random(suspects) + ' in the ' + current_room + ' with the ' + random(weapons) '!';
|
||||||
|
};
|
130
src/interface.rs
130
src/interface.rs
@ -47,18 +47,25 @@ pub fn eval_with_context(source: &str, context: &mut VariableMap) -> Vec<Result<
|
|||||||
|
|
||||||
let tree = parser.parse(source, None).unwrap();
|
let tree = parser.parse(source, None).unwrap();
|
||||||
let sexp = tree.root_node().to_sexp();
|
let sexp = tree.root_node().to_sexp();
|
||||||
let evaluator = Evaluator::new(tree.clone(), source).unwrap();
|
|
||||||
let mut cursor = tree.walk();
|
let mut cursor = tree.walk();
|
||||||
let results = evaluator.run(context, &mut cursor, source);
|
|
||||||
|
|
||||||
println!("{sexp}");
|
println!("{sexp}");
|
||||||
|
|
||||||
|
let evaluator = Evaluator::new(tree.clone(), source).unwrap();
|
||||||
println!("{evaluator:?}");
|
println!("{evaluator:?}");
|
||||||
|
|
||||||
|
let results = evaluator.run(context, &mut cursor, source);
|
||||||
println!("{results:?}");
|
println!("{results:?}");
|
||||||
println!("{context:?}");
|
println!("{context:?}");
|
||||||
|
|
||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A collection of statements and comments interpreted from a syntax tree.
|
||||||
|
///
|
||||||
|
/// The Evaluator turns a tree sitter concrete syntax tree into a vector of
|
||||||
|
/// trees that can be run to execute the source code. Each of these trees is an
|
||||||
|
/// [Item][] in the evaluator.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Evaluator {
|
struct Evaluator {
|
||||||
items: Vec<Item>,
|
items: Vec<Item>,
|
||||||
@ -66,14 +73,11 @@ struct Evaluator {
|
|||||||
|
|
||||||
impl Evaluator {
|
impl Evaluator {
|
||||||
fn new(tree: Tree, source: &str) -> Result<Self> {
|
fn new(tree: Tree, source: &str) -> Result<Self> {
|
||||||
let mut cursor = tree.walk();
|
let root_node = tree.root_node();
|
||||||
let root_node = cursor.node();
|
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
|
|
||||||
for node in root_node.children(&mut cursor) {
|
let item = Item::new(root_node, source)?;
|
||||||
let item = Item::new(node, source)?;
|
|
||||||
items.push(item);
|
items.push(item);
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Evaluator { items })
|
Ok(Evaluator { items })
|
||||||
}
|
}
|
||||||
@ -99,6 +103,11 @@ impl Evaluator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An abstractiton of an independent unit of source code.
|
||||||
|
///
|
||||||
|
/// Items are either comments, which do nothing, or statements, which can be run
|
||||||
|
/// to produce a single value or interact with a context by creating or
|
||||||
|
/// referencing variables.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Item {
|
enum Item {
|
||||||
Comment(String),
|
Comment(String),
|
||||||
@ -107,12 +116,21 @@ enum Item {
|
|||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
fn new(node: Node, source: &str) -> Result<Self> {
|
fn new(node: Node, source: &str) -> Result<Self> {
|
||||||
if node.kind() == "comment" {
|
if node.kind() != "item" {
|
||||||
|
return Err(Error::UnexpectedSourceNode {
|
||||||
|
expected: "item",
|
||||||
|
actual: node.kind(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let child = node.child(0).unwrap();
|
||||||
|
|
||||||
|
if child.kind() == "comment" {
|
||||||
let byte_range = node.byte_range();
|
let byte_range = node.byte_range();
|
||||||
let value_string = &source[byte_range];
|
let value_string = &source[byte_range];
|
||||||
|
|
||||||
Ok(Item::Comment(value_string.to_string()))
|
Ok(Item::Comment(value_string.to_string()))
|
||||||
} else if node.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)?))
|
||||||
} else {
|
} else {
|
||||||
@ -134,7 +152,7 @@ impl Statement {
|
|||||||
fn new(node: Node, source: &str) -> Result<Self> {
|
fn new(node: Node, source: &str) -> Result<Self> {
|
||||||
let child = node.child(0).unwrap();
|
let child = node.child(0).unwrap();
|
||||||
|
|
||||||
match node.kind() {
|
match child.kind() {
|
||||||
"closed_statement" => Ok(Statement::Closed(Expression::new(child, source)?)),
|
"closed_statement" => Ok(Statement::Closed(Expression::new(child, source)?)),
|
||||||
"open_statement" => Ok(Self::Open(Expression::new(child, source)?)),
|
"open_statement" => Ok(Self::Open(Expression::new(child, source)?)),
|
||||||
_ => Err(Error::UnexpectedSourceNode {
|
_ => Err(Error::UnexpectedSourceNode {
|
||||||
@ -165,19 +183,13 @@ impl Statement {
|
|||||||
enum Expression {
|
enum Expression {
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
Value(Value),
|
Value(Value),
|
||||||
Operation(Operation),
|
Operation(Box<Operation>),
|
||||||
|
ControlFlow(Box<ControlFlow>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
fn new(node: Node, source: &str) -> Result<Self> {
|
fn new(node: Node, source: &str) -> Result<Self> {
|
||||||
if node.kind() != "expression" {
|
let child = node.child(0).unwrap().child(0).unwrap();
|
||||||
return Err(Error::UnexpectedSourceNode {
|
|
||||||
expected: "expression",
|
|
||||||
actual: node.kind(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let child = node.child(0).unwrap();
|
|
||||||
|
|
||||||
if child.kind() == "identifier" {
|
if child.kind() == "identifier" {
|
||||||
let byte_range = child.byte_range();
|
let byte_range = child.byte_range();
|
||||||
@ -187,10 +199,16 @@ impl Expression {
|
|||||||
} else if child.kind() == "value" {
|
} else if child.kind() == "value" {
|
||||||
Ok(Expression::Value(Value::new(child, source)?))
|
Ok(Expression::Value(Value::new(child, source)?))
|
||||||
} else if child.kind() == "operation" {
|
} else if child.kind() == "operation" {
|
||||||
Ok(Expression::Operation(Operation::new(child, source)?))
|
Ok(Expression::Operation(Box::new(Operation::new(
|
||||||
|
child, source,
|
||||||
|
)?)))
|
||||||
|
} else if child.kind() == "control_flow" {
|
||||||
|
Ok(Expression::ControlFlow(Box::new(ControlFlow::new(
|
||||||
|
child, source,
|
||||||
|
)?)))
|
||||||
} else {
|
} else {
|
||||||
Err(Error::UnexpectedSourceNode {
|
Err(Error::UnexpectedSourceNode {
|
||||||
expected: "identifier, operation or value",
|
expected: "identifier, operation, control_flow or value",
|
||||||
actual: child.kind(),
|
actual: child.kind(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -214,25 +232,28 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
Expression::Value(value) => Ok(value.clone()),
|
Expression::Value(value) => Ok(value.clone()),
|
||||||
Expression::Operation(operation) => operation.run(context, &mut cursor, source),
|
Expression::Operation(operation) => operation.run(context, &mut cursor, source),
|
||||||
|
Expression::ControlFlow(control_flow) => control_flow.run(context, &mut cursor, source),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Operation {
|
struct Operation {
|
||||||
left: Box<Expression>,
|
left: Expression,
|
||||||
operator: String,
|
operator: String,
|
||||||
right: Box<Expression>,
|
right: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operation {
|
impl Operation {
|
||||||
fn new(node: Node, source: &str) -> Result<Self> {
|
fn new(node: Node, source: &str) -> Result<Self> {
|
||||||
|
println!("{node:?}");
|
||||||
|
|
||||||
let first_child = node.child(0).unwrap();
|
let first_child = node.child(0).unwrap();
|
||||||
let second_child = node.child(1).unwrap();
|
let second_child = node.child(1).unwrap();
|
||||||
let third_child = node.child(2).unwrap();
|
let third_child = node.child(2).unwrap();
|
||||||
let left = { Box::new(Expression::new(first_child, source)?) };
|
let left = Expression::new(first_child, source)?;
|
||||||
let operator = { second_child.child(0).unwrap().kind().to_string() };
|
let operator = second_child.child(0).unwrap().kind().to_string();
|
||||||
let right = { Box::new(Expression::new(third_child, source)?) };
|
let right = Expression::new(third_child, source)?;
|
||||||
|
|
||||||
Ok(Operation {
|
Ok(Operation {
|
||||||
left,
|
left,
|
||||||
@ -252,7 +273,7 @@ impl Operation {
|
|||||||
let result = match self.operator.as_str() {
|
let result = match self.operator.as_str() {
|
||||||
"+" => left + right,
|
"+" => left + right,
|
||||||
"=" => {
|
"=" => {
|
||||||
if let Expression::Identifier(key) = self.left.as_ref() {
|
if let Expression::Identifier(key) = &self.left {
|
||||||
context.set_value(key, right)?;
|
context.set_value(key, right)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,6 +286,53 @@ impl Operation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ControlFlow {
|
||||||
|
if_expression: Expression,
|
||||||
|
then_statement: Statement,
|
||||||
|
else_statement: Option<Statement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ControlFlow {
|
||||||
|
fn new(node: Node, source: &str) -> Result<Self> {
|
||||||
|
let second_child = node.child(1).unwrap();
|
||||||
|
let fourth_child = node.child(3).unwrap();
|
||||||
|
let fifth_child = node.child(4);
|
||||||
|
println!("{second_child:?} {fourth_child:?} {fifth_child:?}");
|
||||||
|
let else_statement = if let Some(child) = fifth_child {
|
||||||
|
Some(Statement::new(child, source)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ControlFlow {
|
||||||
|
if_expression: Expression::new(second_child, source)?,
|
||||||
|
then_statement: Statement::new(fourth_child, source)?,
|
||||||
|
else_statement,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
context: &mut VariableMap,
|
||||||
|
mut cursor: &mut TreeCursor,
|
||||||
|
source: &str,
|
||||||
|
) -> Result<Value> {
|
||||||
|
let if_boolean = self
|
||||||
|
.if_expression
|
||||||
|
.run(context, &mut cursor, source)?
|
||||||
|
.as_boolean()?;
|
||||||
|
|
||||||
|
if if_boolean {
|
||||||
|
self.then_statement.run(context, &mut cursor, source)
|
||||||
|
} else if let Some(statement) = &self.else_statement {
|
||||||
|
statement.run(context, &mut cursor, source)
|
||||||
|
} else {
|
||||||
|
Ok(Value::Empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -285,4 +353,12 @@ mod tests {
|
|||||||
fn evaluate_string() {
|
fn evaluate_string() {
|
||||||
assert_eq!(eval("'one'"), vec![Ok(Value::String("one".to_string()))]);
|
assert_eq!(eval("'one'"), vec![Ok(Value::String("one".to_string()))]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_else() {
|
||||||
|
assert_eq!(
|
||||||
|
eval("if true then 'true'"),
|
||||||
|
vec![Ok(Value::String("true".to_string()))]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,11 @@ impl Value {
|
|||||||
|
|
||||||
Ok(Value::String(without_quotes.to_string()))
|
Ok(Value::String(without_quotes.to_string()))
|
||||||
}
|
}
|
||||||
|
"boolean" => {
|
||||||
|
let raw = value_snippet.parse::<bool>().unwrap_or_default();
|
||||||
|
|
||||||
|
Ok(Value::Boolean(raw))
|
||||||
|
}
|
||||||
"empty" => Ok(Value::Empty),
|
"empty" => Ok(Value::Empty),
|
||||||
_ => Err(Error::UnexpectedSourceNode {
|
_ => Err(Error::UnexpectedSourceNode {
|
||||||
expected: "raw value",
|
expected: "raw value",
|
||||||
|
Loading…
Reference in New Issue
Block a user