checkpoint
This commit is contained in:
@@ -124,6 +124,7 @@ pub enum Expression {
|
||||
Reference(Location, String),
|
||||
Cast(Location, String, Box<Expression>),
|
||||
Primitive(Location, String, Vec<Expression>),
|
||||
Block(Location, Vec<Statement>),
|
||||
}
|
||||
|
||||
impl PartialEq for Expression {
|
||||
@@ -145,6 +146,10 @@ impl PartialEq for Expression {
|
||||
Expression::Primitive(_, prim2, args2) => prim1 == prim2 && args1 == args2,
|
||||
_ => false,
|
||||
},
|
||||
Expression::Block(_, stmts1) => match other {
|
||||
Expression::Block(_, stmts2) => stmts1 == stmts2,
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,25 +35,7 @@ impl Program {
|
||||
}
|
||||
}
|
||||
|
||||
TopLevel::Statement(Statement::Binding(_, name, value)) => {
|
||||
let actual_value = value.eval(&env)?;
|
||||
env.insert(name.clone().intern(), actual_value);
|
||||
last_result = Value::Void;
|
||||
}
|
||||
|
||||
TopLevel::Statement(Statement::Print(loc, name)) => {
|
||||
let value = env
|
||||
.get(&name.clone().intern())
|
||||
.ok_or_else(|| EvalError::LookupFailed(loc.clone(), name.name.clone()))?;
|
||||
let value = if let Value::Number(x) = value {
|
||||
Value::U64(*x)
|
||||
} else {
|
||||
value.clone()
|
||||
};
|
||||
let line = format!("{} = {}\n", name, value);
|
||||
stdout.push_str(&line);
|
||||
last_result = Value::Void;
|
||||
}
|
||||
TopLevel::Statement(stmt) => last_result = stmt.eval(&mut stdout, &mut env)?,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,10 +43,41 @@ impl Program {
|
||||
}
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
fn eval(
|
||||
&self,
|
||||
stdout: &mut String,
|
||||
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())
|
||||
.ok_or_else(|| EvalError::LookupFailed(loc.clone(), name.name.clone()))?;
|
||||
let value = if let Value::Number(x) = value {
|
||||
Value::U64(*x)
|
||||
} else {
|
||||
value.clone()
|
||||
};
|
||||
let line = format!("{} = {}\n", name, value);
|
||||
stdout.push_str(&line);
|
||||
Ok(Value::Void)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
fn eval(
|
||||
&self,
|
||||
env: &ScopedMap<ArcIntern<String>, Value<Expression>>,
|
||||
stdout: &mut String,
|
||||
env: &mut ScopedMap<ArcIntern<String>, Value<Expression>>,
|
||||
) -> Result<Value<Expression>, EvalError<Expression>> {
|
||||
match self {
|
||||
Expression::Value(_, v) => match v {
|
||||
@@ -90,7 +103,7 @@ impl Expression {
|
||||
|
||||
Expression::Cast(_, target, expr) => {
|
||||
let target_type = PrimitiveType::from_str(target)?;
|
||||
let value = expr.eval(env)?;
|
||||
let value = expr.eval(stdout, env)?;
|
||||
Ok(target_type.safe_cast(&value)?)
|
||||
}
|
||||
|
||||
@@ -99,11 +112,21 @@ impl Expression {
|
||||
|
||||
for arg in args.iter() {
|
||||
// yay, recursion! makes this pretty straightforward
|
||||
arg_values.push(arg.eval(env)?);
|
||||
arg_values.push(arg.eval(stdout, env)?);
|
||||
}
|
||||
|
||||
Ok(Value::calculate(op, arg_values)?)
|
||||
}
|
||||
|
||||
Expression::Block(_, stmts) => {
|
||||
let mut result = Value::Void;
|
||||
|
||||
for stmt in stmts.iter() {
|
||||
result = stmt.eval(stdout, env)?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,11 +87,13 @@ OptionalName: Option<Name> = {
|
||||
}
|
||||
|
||||
Arguments: Vec<Name> = {
|
||||
<mut args:Arguments> <arg:Argument> => {
|
||||
<mut args:Arguments> "," <arg:Argument> => {
|
||||
args.push(arg);
|
||||
args
|
||||
},
|
||||
|
||||
<arg:Argument> => vec![arg],
|
||||
|
||||
=> Vec::new(),
|
||||
}
|
||||
|
||||
@@ -214,7 +216,7 @@ AtomicExpression: Expression = {
|
||||
// just a number
|
||||
<l: @L> <n:"<num>"> <end: @L> => Expression::Value(Location::new(file_idx, l..end), Value::Number(n.0, n.1, n.2)),
|
||||
// this expression could actually be a block!
|
||||
"{" <stmts:Statements> "}" => unimplemented!(),
|
||||
<s:@L> "{" <stmts:Statements> "}" <e:@L> => Expression::Block(Location::new(file_idx, s..e), stmts),
|
||||
// finally, let people parenthesize expressions and get back to a
|
||||
// lower precedence
|
||||
"(" <e:Expression> ")" => e,
|
||||
|
||||
@@ -105,6 +105,25 @@ where
|
||||
let comma_sepped_args = allocator.intersperse(args, CommaSep {});
|
||||
call.append(comma_sepped_args.parens())
|
||||
}
|
||||
Expression::Block(_, stmts) => match stmts.split_last() {
|
||||
None => allocator.text("()"),
|
||||
Some((last, &[])) => last.pretty(allocator),
|
||||
Some((last, start)) => {
|
||||
let mut result = allocator.text("{").append(allocator.hardline());
|
||||
|
||||
for stmt in start.iter() {
|
||||
result = result
|
||||
.append(stmt.pretty(allocator))
|
||||
.append(allocator.text(";"))
|
||||
.append(allocator.hardline());
|
||||
}
|
||||
|
||||
result
|
||||
.append(last.pretty(allocator))
|
||||
.append(allocator.hardline())
|
||||
.append(allocator.text("}"))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,10 @@ impl Statement {
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
fn validate(&self, variable_map: &ScopedMap<String, Location>) -> (Vec<Error>, Vec<Warning>) {
|
||||
fn validate(
|
||||
&self,
|
||||
variable_map: &mut ScopedMap<String, Location>,
|
||||
) -> (Vec<Error>, Vec<Warning>) {
|
||||
match self {
|
||||
Expression::Value(_, _) => (vec![], vec![]),
|
||||
Expression::Reference(_, var) if variable_map.contains_key(var) => (vec![], vec![]),
|
||||
@@ -207,6 +210,19 @@ impl Expression {
|
||||
warnings.append(&mut warn);
|
||||
}
|
||||
|
||||
(errors, warnings)
|
||||
}
|
||||
Expression::Block(_, stmts) => {
|
||||
let mut errors = vec![];
|
||||
let mut warnings = vec![];
|
||||
|
||||
for stmt in stmts.iter() {
|
||||
let (mut local_errors, mut local_warnings) = stmt.validate(variable_map);
|
||||
|
||||
errors.append(&mut local_errors);
|
||||
warnings.append(&mut local_warnings);
|
||||
}
|
||||
|
||||
(errors, warnings)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user