Implement more statements

Added variable declaration, `if` statements, `loop` statements,
variable assignment, and variable banning to go along with
printing (which was already implemented). We still need function
declarations, brainfuck declarations, function calls, and the control
flow operators "break" and "hopback".
This commit is contained in:
Alexander Bethel 2021-05-23 18:46:42 -05:00
parent b37c189da9
commit 1c2032ab87
2 changed files with 81 additions and 21 deletions

View file

@ -21,7 +21,6 @@ use crate::{
pub struct Scope {
/// The mapping from variable names to values.
variables: HashMap<String, Variable>,
// In the future, this will store functio definitions, a link to a
// parent scope (so we can have nested scopes), and possibly other
// information.
@ -82,13 +81,13 @@ impl Scope {
}
Eq { left, right } => Bool(self.eval_expr(left)? == self.eval_expr(right)?),
Neq { left, right } => Bool(self.eval_expr(left)? != self.eval_expr(right)?),
And { left, right } => Bool(
bool::try_from(self.eval_expr(left)?)? && bool::try_from(self.eval_expr(right)?)?,
),
Or { left, right } => Bool(
bool::try_from(self.eval_expr(left)?)? || bool::try_from(self.eval_expr(right)?)?,
),
Not(expr) => Bool(!bool::try_from(self.eval_expr(expr)?)?),
And { left, right } => {
Bool(bool::from(self.eval_expr(left)?) && bool::from(self.eval_expr(right)?))
}
Or { left, right } => {
Bool(bool::from(self.eval_expr(left)?) || bool::from(self.eval_expr(right)?))
}
Not(expr) => Bool(!bool::from(self.eval_expr(expr)?)),
Literal(value) => value.clone(),
Identifier(Iden(name)) => self
.variables
@ -117,11 +116,66 @@ impl Scope {
match stmt {
Stmt::Print(expr) => {
println!("{}", self.eval_expr(expr)?);
Ok(())
}
_ => {
todo!()
Stmt::VariableDeclaration { iden, init } => {
self.variables.insert(
iden.0.clone(),
Variable {
melo: false,
value: match init {
Some(init) => self.eval_expr(init)?,
None => Value::Nul,
},
},
);
}
Stmt::FunctionDeclaration {
iden: _,
args: _,
body: _,
} => todo!(),
Stmt::BfFDeclaration { iden: _, body: _ } => todo!(),
Stmt::If { cond, body } => {
if self.eval_expr(cond)?.into() {
self.eval_items(body)?;
}
}
Stmt::FunctionCall { iden: _, args: _ } => todo!(),
Stmt::Loop { body } => {
loop {
// For now, loops run forever until they reach an
// error.
self.eval_items(body)?;
}
}
Stmt::VarAssignment { iden, value } => {
let value = self.eval_expr(value)?;
let record = self.variables.get_mut(&iden.0).ok_or_else(|| Error {
kind: ErrorKind::UnknownVariable(iden.0.clone()),
position: 0..0,
})?;
if record.melo {
return Err(Error {
kind: ErrorKind::MeloVariable(iden.0.clone()),
position: 0..0,
});
}
record.value = value;
}
Stmt::Break => todo!(),
Stmt::HopBack => todo!(),
Stmt::Melo(iden) => {
let record = self.variables.get_mut(&iden.0).ok_or_else(|| Error {
kind: ErrorKind::UnknownVariable(iden.0.clone()),
position: 0..0,
})?;
record.melo = true;
}
}
Ok(())
}
}

View file

@ -71,17 +71,23 @@ impl TryFrom<Value> for i32 {
}
}
impl TryFrom<Value> for bool {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
// Coercions from a value to a boolean always succeed, so every value
// can be used in an `if` statement. C does things that way, so how
// could it possibly be a bad idea?
impl From<Value> for bool {
fn from(value: Value) -> Self {
match value {
Value::Bool(b) => Ok(b),
Value::Abool(b) => Ok(b.into()),
_ => Err(Error {
kind: ErrorKind::TypeError(format!("Expected bool, got {}", value)),
position: 0..0,
}),
// Booleans and abooleans have a trivial conversion.
Value::Bool(b) => b,
Value::Abool(b) => b.into(),
// The empty string is falsey, other strings are truthy.
Value::Str(s) => s.len() != 0,
// 0 is falsey, nonzero is truthy.
Value::Int(x) => x != 0,
// And nul is truthy as a symbol of the fact that the
// deep, fundamental truth of this world is nothing but
// the eternal void.
Value::Nul => true,
}
}
}