Allow chained equals.
This commit is contained in:
@@ -72,11 +72,11 @@ impl Arbitrary for Program {
|
||||
genenv.bindings.insert(psi.name.clone(), psi.binding_type);
|
||||
items.push(
|
||||
expr.prop_map(move |expr| {
|
||||
TopLevel::Statement(Statement::Binding(
|
||||
TopLevel::Statement(Statement::Expression(Expression::Binding(
|
||||
Location::manufactured(),
|
||||
psi.name.clone(),
|
||||
expr,
|
||||
))
|
||||
Box::new(expr),
|
||||
)))
|
||||
})
|
||||
.boxed(),
|
||||
);
|
||||
|
||||
@@ -99,7 +99,6 @@ impl fmt::Display for Name {
|
||||
/// thing, not if they are the exact same statement.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Statement {
|
||||
Binding(Location, Name, Expression),
|
||||
Print(Location, Name),
|
||||
Expression(Expression),
|
||||
}
|
||||
@@ -107,10 +106,6 @@ pub enum Statement {
|
||||
impl PartialEq for Statement {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match self {
|
||||
Statement::Binding(_, name1, expr1) => match other {
|
||||
Statement::Binding(_, name2, expr2) => name1 == name2 && expr1 == expr2,
|
||||
_ => false,
|
||||
},
|
||||
Statement::Print(_, name1) => match other {
|
||||
Statement::Print(_, name2) => name1 == name2,
|
||||
_ => false,
|
||||
@@ -139,6 +134,7 @@ pub enum Expression {
|
||||
Primitive(Location, String, Vec<Expression>),
|
||||
Call(Location, Box<Expression>, Vec<Expression>),
|
||||
Block(Location, Vec<Statement>),
|
||||
Binding(Location, Name, Box<Expression>),
|
||||
}
|
||||
|
||||
impl PartialEq for Expression {
|
||||
@@ -176,6 +172,10 @@ impl PartialEq for Expression {
|
||||
Expression::Block(_, stmts2) => stmts1 == stmts2,
|
||||
_ => false,
|
||||
},
|
||||
Expression::Binding(_, name1, expr1) => match other {
|
||||
Expression::Binding(_, name2, expr2) => name1 == name2 && expr1 == expr2,
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,6 +192,7 @@ impl Expression {
|
||||
Expression::Primitive(loc, _, _) => loc,
|
||||
Expression::Call(loc, _, _) => loc,
|
||||
Expression::Block(loc, _) => loc,
|
||||
Expression::Binding(loc, _, _) => loc,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,12 +59,6 @@ impl Statement {
|
||||
env: &mut ScopedMap<ArcIntern<String>, Value<Expression>>,
|
||||
) -> Result<Value<Expression>, EvalError<Expression>> {
|
||||
match self {
|
||||
Statement::Binding(_, name, value) => {
|
||||
let actual_value = value.eval(stdout, env)?;
|
||||
env.insert(name.clone().intern(), actual_value);
|
||||
Ok(Value::Void)
|
||||
}
|
||||
|
||||
Statement::Print(loc, name) => {
|
||||
let value = env
|
||||
.get(&name.clone().intern())
|
||||
@@ -197,6 +191,12 @@ impl Expression {
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
Expression::Binding(_, name, value) => {
|
||||
let actual_value = value.eval(stdout, env)?;
|
||||
env.insert(name.clone().intern(), actual_value.clone());
|
||||
Ok(actual_value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,16 +148,6 @@ Statements: Vec<Statement> = {
|
||||
|
||||
#[inline]
|
||||
Statement: Statement = {
|
||||
// A statement can be a variable binding. Note, here, that we use this
|
||||
// funny @L thing to get the source location before the variable, so that
|
||||
// we can say that this statement spans across everything.
|
||||
<ls: @L> <v:"<var>"> <var_end: @L> "=" <e:Expression> <le: @L> =>
|
||||
Statement::Binding(
|
||||
Location::new(file_idx, ls..le),
|
||||
Name::new(v, Location::new(file_idx, ls..var_end)),
|
||||
e,
|
||||
),
|
||||
|
||||
// A statement can just be a print statement.
|
||||
<ls: @L> "print" <name_start: @L> <v:"<var>"> <name_end: @L> <le: @L> =>
|
||||
Statement::Print(
|
||||
@@ -194,13 +184,27 @@ Statement: Statement = {
|
||||
// parse something like "1 + 2 * 3", for example, versus "1 + 2 + 3" or
|
||||
// "1 * 2 + 3", and hopefully that'll help.
|
||||
Expression: Expression = {
|
||||
BindingExpression,
|
||||
}
|
||||
|
||||
BindingExpression: Expression = {
|
||||
// An expression can be a variable binding. Note, here, that we use this
|
||||
// funny @L thing to get the source location before the variable, so that
|
||||
// we can say that this statement spans across everything.
|
||||
<ls: @L> <v:"<var>"> <var_end: @L> "=" <e:BindingExpression> <le: @L> =>
|
||||
Expression::Binding(
|
||||
Location::new(file_idx, ls..le),
|
||||
Name::new(v, Location::new(file_idx, ls..var_end)),
|
||||
Box::new(e),
|
||||
),
|
||||
|
||||
ConstructorExpression,
|
||||
AdditiveExpression,
|
||||
}
|
||||
|
||||
ConstructorExpression: Expression = {
|
||||
<s:@L> <name:TypeName> "{" <fields:FieldSetter*> "}" <e:@L> =>
|
||||
Expression::Constructor(Location::new(file_idx, s..e), name, fields),
|
||||
AdditiveExpression,
|
||||
}
|
||||
|
||||
FieldSetter: (Name, Expression) = {
|
||||
|
||||
@@ -90,12 +90,6 @@ impl TopLevel {
|
||||
impl Statement {
|
||||
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||
match self {
|
||||
Statement::Binding(_, var, expr) => allocator
|
||||
.text(var.to_string())
|
||||
.append(allocator.space())
|
||||
.append(allocator.text("="))
|
||||
.append(allocator.space())
|
||||
.append(expr.pretty(allocator)),
|
||||
Statement::Print(_, var) => allocator
|
||||
.text("print")
|
||||
.append(allocator.space())
|
||||
@@ -178,6 +172,12 @@ impl Expression {
|
||||
.append(allocator.text("}"))
|
||||
}
|
||||
},
|
||||
Expression::Binding(_, var, expr) => allocator
|
||||
.text(var.to_string())
|
||||
.append(allocator.space())
|
||||
.append(allocator.text("="))
|
||||
.append(allocator.space())
|
||||
.append(expr.pretty(allocator)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,25 +156,6 @@ impl Statement {
|
||||
let mut warnings = vec![];
|
||||
|
||||
match self {
|
||||
Statement::Binding(loc, var, val) => {
|
||||
// we're going to make the decision that a variable is not bound in the right
|
||||
// hand side of its binding, which makes a lot of things easier. So we'll just
|
||||
// immediately check the expression, and go from there.
|
||||
let (mut exp_errors, mut exp_warnings) = val.validate(bound_variables);
|
||||
|
||||
errors.append(&mut exp_errors);
|
||||
warnings.append(&mut exp_warnings);
|
||||
if let Some(original_binding_site) = bound_variables.get(&var.name) {
|
||||
warnings.push(Warning::ShadowedVariable(
|
||||
original_binding_site.clone(),
|
||||
loc.clone(),
|
||||
var.to_string(),
|
||||
));
|
||||
} else {
|
||||
bound_variables.insert(var.to_string(), loc.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Statement::Print(_, var) if bound_variables.contains_key(&var.name) => {}
|
||||
Statement::Print(loc, var) => {
|
||||
errors.push(Error::UnboundVariable(loc.clone(), var.to_string()))
|
||||
@@ -260,6 +241,24 @@ impl Expression {
|
||||
warnings.append(&mut local_warnings);
|
||||
}
|
||||
|
||||
(errors, warnings)
|
||||
}
|
||||
Expression::Binding(loc, var, val) => {
|
||||
// we're going to make the decision that a variable is not bound in the right
|
||||
// hand side of its binding, which makes a lot of things easier. So we'll just
|
||||
// immediately check the expression, and go from there.
|
||||
let (errors, mut warnings) = val.validate(variable_map);
|
||||
|
||||
if let Some(original_binding_site) = variable_map.get(&var.name) {
|
||||
warnings.push(Warning::ShadowedVariable(
|
||||
original_binding_site.clone(),
|
||||
loc.clone(),
|
||||
var.to_string(),
|
||||
));
|
||||
} else {
|
||||
variable_map.insert(var.to_string(), loc.clone());
|
||||
}
|
||||
|
||||
(errors, warnings)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user