forked from AbleScript/ablescript
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:
parent
c27837a807
commit
109c77eeb2
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue