Compare commits

..

No commits in common. "4c6a93302d260ffa26f2efd69777336b2040cc42" and "76f7524fdbbefb5446f41229a276fc2b33a9b820" have entirely different histories.

14 changed files with 47 additions and 334 deletions

View File

@ -1,10 +1,5 @@
# Immediate TODOs / General Code Cleanup # Immediate TODOs / General Code Cleanup
## Evaluator
* Make the evaluator take ReducedIR items by reference
## Testing ## Testing
* Make an automatic (macro-based?) system for numbering compiler errors, this should be every type of error * Make an automatic (macro-based?) system for numbering compiler errors, this should be every type of error

View File

@ -54,14 +54,6 @@ pub enum StatementKind {
Declaration(Declaration), Declaration(Declaration),
Import(ImportSpecifier), Import(ImportSpecifier),
Module(ModuleSpecifier), Module(ModuleSpecifier),
Flow(FlowControl),
}
#[derive(Debug, Clone, PartialEq)]
pub enum FlowControl {
Continue,
Break,
Return(Option<Expression>),
} }
#[derive(Debug, Clone, PartialEq, Default)] #[derive(Debug, Clone, PartialEq, Default)]

View File

@ -47,12 +47,6 @@ pub fn walk_block<V: ASTVisitor>(v: &mut V, block: &Block) {
if let Recursion::Continue = v.module(module_spec) { if let Recursion::Continue = v.module(module_spec) {
walk_block(v, &module_spec.contents); walk_block(v, &module_spec.contents);
}, },
Flow(ref flow_control) => match flow_control {
FlowControl::Return(Some(ref retval)) => {
walk_expression(v, retval);
}
_ => (),
},
} }
} }
} }

View File

@ -1,9 +1,7 @@
#![allow(clippy::single_char_add_str)] #![allow(clippy::single_char_add_str)]
use std::fmt::Write;
use super::{ use super::{
Block, Declaration, Expression, ExpressionKind, FlowControl, ImportSpecifier, InvocationArgument, Block, Declaration, Expression, ExpressionKind, ImportSpecifier, InvocationArgument, ModuleSpecifier,
ModuleSpecifier, Signature, Statement, StatementKind, AST, Signature, Statement, StatementKind, AST,
}; };
const LEVEL: usize = 2; const LEVEL: usize = 2;
@ -37,7 +35,6 @@ fn render_statement(stmt: &Statement, indent: usize, buf: &mut String) {
Declaration(ref decl) => render_declaration(decl, indent, buf), Declaration(ref decl) => render_declaration(decl, indent, buf),
Import(ref spec) => render_import(spec, indent, buf), Import(ref spec) => render_import(spec, indent, buf),
Module(ref spec) => render_module(spec, indent, buf), Module(ref spec) => render_module(spec, indent, buf),
Flow(ref flow_control) => render_flow_control(flow_control, indent, buf),
} }
} }
@ -194,15 +191,6 @@ fn render_module(_expr: &ModuleSpecifier, _indent: usize, buf: &mut String) {
buf.push_str("(Module <some mod>)"); buf.push_str("(Module <some mod>)");
} }
fn render_flow_control(flow: &FlowControl, _indent: usize, buf: &mut String) {
use FlowControl::*;
match flow {
Return(ref _expr) => write!(buf, "return <expr>").unwrap(),
Break => write!(buf, "break").unwrap(),
Continue => write!(buf, "continue").unwrap(),
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::render_ast; use super::render_ast;

View File

@ -33,7 +33,6 @@ pub enum Builtin {
IOGetLine, IOGetLine,
Assignment, Assignment,
Concatenate, Concatenate,
NotEqual,
} }
impl Builtin { impl Builtin {
@ -66,7 +65,6 @@ impl Builtin {
Concatenate => ty!(StringT -> StringT -> StringT), Concatenate => ty!(StringT -> StringT -> StringT),
Increment => ty!(Nat -> Int), Increment => ty!(Nat -> Int),
Negate => ty!(Nat -> Int), Negate => ty!(Nat -> Int),
NotEqual => ty!(Nat -> Nat -> Bool),
} }
} }
} }
@ -118,7 +116,6 @@ impl FromStr for Builtin {
"<" => LessThan, "<" => LessThan,
"<=" => LessThanOrEqual, "<=" => LessThanOrEqual,
"==" => Equality, "==" => Equality,
"!=" => NotEqual,
"=" => Assignment, "=" => Assignment,
"<=>" => Comparison, "<=>" => Comparison,
"print" => IOPrint, "print" => IOPrint,

View File

@ -15,7 +15,7 @@
//! ```text //! ```text
//! program := (statement delimiter)* EOF //! program := (statement delimiter)* EOF
//! delimiter := NEWLINE | ";" //! delimiter := NEWLINE | ";"
//! statement := expression | declaration | import | module | flow //! statement := expression | declaration | import | module
//! block := "{" (statement delimiter)* "}" //! block := "{" (statement delimiter)* "}"
//! declaration := type_declaration | func_declaration | binding_declaration | impl_declaration //! declaration := type_declaration | func_declaration | binding_declaration | impl_declaration
//! ``` //! ```
@ -401,28 +401,12 @@ impl Parser {
Keyword(Impl) => self.impl_declaration().map(StatementKind::Declaration), Keyword(Impl) => self.impl_declaration().map(StatementKind::Declaration),
Keyword(Import) => self.import_declaration().map(StatementKind::Import), Keyword(Import) => self.import_declaration().map(StatementKind::Import),
Keyword(Module) => self.module_declaration().map(StatementKind::Module), Keyword(Module) => self.module_declaration().map(StatementKind::Module),
Keyword(Continue) | Keyword(Return) | Keyword(Break) =>
self.flow_control().map(StatementKind::Flow),
_ => self.expression().map(StatementKind::Expression), _ => self.expression().map(StatementKind::Expression),
}?; }?;
let id = self.id_store.fresh(); let id = self.id_store.fresh();
Ok(Statement { kind, id, location: tok.location }) Ok(Statement { kind, id, location: tok.location })
} }
#[recursive_descent_method]
fn flow_control(&mut self) -> ParseResult<FlowControl> {
let tok = self.token_handler.next();
Ok(match tok.get_kind() {
Keyword(Continue) => FlowControl::Continue,
Keyword(Break) => FlowControl::Break,
Keyword(Return) => match self.token_handler.peek_kind() {
Semicolon | Newline => FlowControl::Return(None),
_ => FlowControl::Return(Some(self.expression()?)),
},
_ => unreachable!(),
})
}
#[recursive_descent_method] #[recursive_descent_method]
fn annotation(&mut self) -> ParseResult<Declaration> { fn annotation(&mut self) -> ParseResult<Declaration> {
expect!(self, AtSign); expect!(self, AtSign);
@ -1123,11 +1107,7 @@ impl Parser {
let pat = self.pattern()?; let pat = self.pattern()?;
(name, pat) (name, pat)
} }
_ => { _ => (name.clone(), Pattern::Literal(PatternLiteral::StringPattern(name))),
let qualified_identifier =
QualifiedName { id: self.id_store.fresh(), components: vec![name.clone()] };
(name, Pattern::VarOrName(qualified_identifier))
}
}) })
} }

View File

@ -1099,7 +1099,10 @@ fn pattern_matching() {
body: bx(IfExpressionBody::SimplePatternMatch { body: bx(IfExpressionBody::SimplePatternMatch {
pattern: Pattern::Record( pattern: Pattern::Record(
qn!(Something), qn!(Something),
vec![(rc("a"), Pattern::VarOrName(qn!(a))), (rc("b"), Pattern::VarOrName(qn!(x)))] vec![
(rc("a"), Pattern::Literal(PatternLiteral::StringPattern(rc("a")))),
(rc("b"), Pattern::VarOrName(qn!(x)))
]
), ),
then_case: vec![exst(NatLiteral(4))].into(), then_case: vec![exst(NatLiteral(4))].into(),
else_case: Some(vec![exst(NatLiteral(9))].into()), else_case: Some(vec![exst(NatLiteral(9))].into()),
@ -1212,38 +1215,3 @@ if (45, "panda", false, 2.2) {
) )
}; };
} }
#[test]
fn flow_control() {
use ExpressionKind::*;
// This is an incorrect program, but shoudl parse correctly.
let source = r#"
fn test() {
let a = 10;
break;
continue;
return;
return 10;
}"#;
assert_ast!(
source,
vec![fn_decl(
Signature { name: rc("test"), operator: false, type_anno: None, params: vec![] },
vec![
decl(Declaration::Binding {
name: rc("a"),
constant: true,
type_anno: None,
expr: expr(NatLiteral(10))
}),
stmt(StatementKind::Flow(FlowControl::Break)),
stmt(StatementKind::Flow(FlowControl::Continue)),
stmt(StatementKind::Flow(FlowControl::Return(None))),
stmt(StatementKind::Flow(FlowControl::Return(Some(expr(NatLiteral(10)))))),
]
.into()
)]
);
}

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, rc::Rc, str::FromStr}; use std::{collections::HashMap, str::FromStr};
use crate::{ use crate::{
ast, ast,
@ -80,9 +80,6 @@ impl<'a, 'b> Reducer<'a, 'b> {
ast::StatementKind::Module(_modspec) => { ast::StatementKind::Module(_modspec) => {
//TODO handle modules //TODO handle modules
} }
ast::StatementKind::Flow(..) => {
//TODO this should be an error
}
} }
} }
@ -103,18 +100,7 @@ impl<'a, 'b> Reducer<'a, 'b> {
_ => None, _ => None,
}, },
ast::StatementKind::Module(_) | ast::StatementKind::Import(_) => { _ => None,
//TODO need to handle function-internal modules, imports
None
}
ast::StatementKind::Flow(ast::FlowControl::Return(expr)) =>
if let Some(expr) = expr {
Some(Statement::Return(self.expression(expr)))
} else {
Some(Statement::Return(Expression::unit()))
},
ast::StatementKind::Flow(ast::FlowControl::Break) => Some(Statement::Break),
ast::StatementKind::Flow(ast::FlowControl::Continue) => Some(Statement::Continue),
} }
} }
@ -149,9 +135,10 @@ impl<'a, 'b> Reducer<'a, 'b> {
}), }),
NamedStruct { name, fields } => { NamedStruct { name, fields } => {
self.symbol_table.debug(); self.symbol_table.debug();
println!("Namedstruct name {} id: {}", name, name.id);
let symbol = self.symbol_table.lookup_symbol(&name.id).unwrap(); let symbol = self.symbol_table.lookup_symbol(&name.id).unwrap();
let (tag, type_id) = match symbol.spec() { let (tag, type_id) = match symbol.spec() {
SymbolSpec::RecordConstructor { tag, type_id } => (tag, type_id), SymbolSpec::RecordConstructor { tag, members: _, type_id } => (tag, type_id),
e => return Expression::ReductionError(format!("Bad symbol for NamedStruct: {:?}", e)), e => return Expression::ReductionError(format!("Bad symbol for NamedStruct: {:?}", e)),
}; };
@ -180,15 +167,7 @@ impl<'a, 'b> Reducer<'a, 'b> {
Expression::Call { f: Box::new(constructor), args: ordered_args } Expression::Call { f: Box::new(constructor), args: ordered_args }
} }
Index { .. } => Expression::ReductionError("Index expr not implemented".to_string()), Index { .. } => Expression::ReductionError("Index expr not implemented".to_string()),
WhileExpression { condition, body } => { WhileExpression { .. } => Expression::ReductionError("While expr not implemented".to_string()),
let cond = Box::new(if let Some(condition) = condition {
self.expression(condition)
} else {
Expression::Literal(Literal::Bool(true))
});
let statements = self.function_internal_block(body);
Expression::Loop { cond, statements }
}
ForExpression { .. } => Expression::ReductionError("For expr not implemented".to_string()), ForExpression { .. } => Expression::ReductionError("For expr not implemented".to_string()),
ListLiteral { .. } => Expression::ReductionError("ListLiteral expr not implemented".to_string()), ListLiteral { .. } => Expression::ReductionError("ListLiteral expr not implemented".to_string()),
Access { name, expr } => Access { name, expr } =>
@ -393,27 +372,11 @@ impl ast::Pattern {
spec => return Err(format!("Unexpected VarOrName symbol: {:?}", spec).into()), spec => return Err(format!("Unexpected VarOrName symbol: {:?}", spec).into()),
} }
} }
ast::Pattern::Record(name, specified_members) => { ast::Pattern::Record(name, _specified_members /*Vec<(Rc<String>, Pattern)>*/) => {
let symbol = symbol_table.lookup_symbol(&name.id).unwrap(); let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
if let SymbolSpec::RecordConstructor { tag, type_id: _ } = symbol.spec() { match symbol.spec() {
//TODO do this computation from the type_id SymbolSpec::RecordConstructor { tag: _, members: _, type_id: _ } => unimplemented!(),
/* spec => return Err(format!("Unexpected Record pattern symbol: {:?}", spec).into()),
if specified_members.iter().any(|(member, _)| !members.contains_key(member)) {
return Err(format!("Unknown key in record pattern").into());
}
*/
let subpatterns: Result<Vec<(Rc<String>, Pattern)>, PatternError> = specified_members
.iter()
.map(|(name, pat)| {
pat.reduce(symbol_table).map(|reduced_pat| (name.clone(), reduced_pat))
})
.into_iter()
.collect();
let subpatterns = subpatterns?;
Pattern::Record { tag, subpatterns }
} else {
return Err(format!("Unexpected Record pattern symbol: {:?}", symbol.spec()).into());
} }
} }
}) })

View File

@ -42,9 +42,6 @@ impl ReducedIR {
pub enum Statement { pub enum Statement {
Expression(Expression), Expression(Expression),
Binding { id: DefId, constant: bool, expr: Expression }, Binding { id: DefId, constant: bool, expr: Expression },
Return(Expression),
Continue,
Break,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -58,7 +55,6 @@ pub enum Expression {
Call { f: Box<Expression>, args: Vec<Expression> }, Call { f: Box<Expression>, args: Vec<Expression> },
Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> }, Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> },
CaseMatch { cond: Box<Expression>, alternatives: Vec<Alternative> }, CaseMatch { cond: Box<Expression>, alternatives: Vec<Alternative> },
Loop { cond: Box<Expression>, statements: Vec<Statement> },
ReductionError(String), ReductionError(String),
} }
@ -108,7 +104,6 @@ pub struct Alternative {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Pattern { pub enum Pattern {
Tuple { subpatterns: Vec<Pattern>, tag: Option<u32> }, Tuple { subpatterns: Vec<Pattern>, tag: Option<u32> },
Record { tag: u32, subpatterns: Vec<(Rc<String>, Pattern)> },
Literal(Literal), Literal(Literal),
Ignored, Ignored,
Binding(DefId), Binding(DefId),

View File

@ -282,7 +282,7 @@ pub enum SymbolSpec {
Builtin(Builtin), Builtin(Builtin),
Func, Func,
DataConstructor { tag: u32, type_id: TypeId }, DataConstructor { tag: u32, type_id: TypeId },
RecordConstructor { tag: u32, type_id: TypeId }, RecordConstructor { tag: u32, members: HashMap<Rc<String>, TypeId>, type_id: TypeId },
GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context
LocalVariable, LocalVariable,
FunctionParam(u8), FunctionParam(u8),
@ -515,7 +515,8 @@ impl<'a> SymbolTableRunner<'a> {
let spec = match &variant.members { let spec = match &variant.members {
type_inference::VariantMembers::Unit => SymbolSpec::DataConstructor { tag, type_id }, type_inference::VariantMembers::Unit => SymbolSpec::DataConstructor { tag, type_id },
type_inference::VariantMembers::Tuple(..) => SymbolSpec::DataConstructor { tag, type_id }, type_inference::VariantMembers::Tuple(..) => SymbolSpec::DataConstructor { tag, type_id },
type_inference::VariantMembers::Record(..) => SymbolSpec::RecordConstructor { tag, type_id }, type_inference::VariantMembers::Record(..) =>
SymbolSpec::RecordConstructor { tag, members: HashMap::new(), type_id },
}; };
self.table.add_symbol(id, fqsn, spec); self.table.add_symbol(id, fqsn, spec);
} }

View File

@ -86,12 +86,11 @@ pub enum Kw {
Func, Func,
For, For,
While, While,
Const,
Let, Let,
In, In,
Mut, Mut,
Return, Return,
Continue,
Break,
Alias, Alias,
Type, Type,
SelfType, SelfType,
@ -116,12 +115,11 @@ impl TryFrom<&str> for Kw {
"fn" => Kw::Func, "fn" => Kw::Func,
"for" => Kw::For, "for" => Kw::For,
"while" => Kw::While, "while" => Kw::While,
"const" => Kw::Const,
"let" => Kw::Let, "let" => Kw::Let,
"in" => Kw::In, "in" => Kw::In,
"mut" => Kw::Mut, "mut" => Kw::Mut,
"return" => Kw::Return, "return" => Kw::Return,
"break" => Kw::Break,
"continue" => Kw::Continue,
"alias" => Kw::Alias, "alias" => Kw::Alias,
"type" => Kw::Type, "type" => Kw::Type,
"Self" => Kw::SelfType, "Self" => Kw::SelfType,

View File

@ -10,30 +10,12 @@ use crate::{
util::ScopeStack, util::ScopeStack,
}; };
#[derive(Debug)]
enum StatementOutput {
Primitive(Primitive),
Nothing,
}
#[derive(Debug, Clone, Copy)]
enum LoopControlFlow {
Break,
Continue,
}
pub struct Evaluator<'a, 'b> { pub struct Evaluator<'a, 'b> {
type_context: &'b TypeContext, pub type_context: &'b TypeContext,
state: &'b mut State<'a>, pub state: &'b mut State<'a>,
early_returning: bool,
loop_control: Option<LoopControlFlow>,
} }
impl<'a, 'b> Evaluator<'a, 'b> { impl<'a, 'b> Evaluator<'a, 'b> {
pub(crate) fn new(state: &'b mut State<'a>, type_context: &'b TypeContext) -> Self {
Self { state, type_context, early_returning: false, loop_control: None }
}
pub fn evaluate(&mut self, reduced: ReducedIR, repl: bool) -> Vec<Result<String, String>> { pub fn evaluate(&mut self, reduced: ReducedIR, repl: bool) -> Vec<Result<String, String>> {
let mut acc = vec![]; let mut acc = vec![];
for (def_id, function) in reduced.functions.into_iter() { for (def_id, function) in reduced.functions.into_iter() {
@ -43,8 +25,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
for statement in reduced.entrypoint.into_iter() { for statement in reduced.entrypoint.into_iter() {
match self.statement(statement) { match self.statement(statement) {
Ok(StatementOutput::Primitive(output)) if repl => Ok(Some(output)) if repl => acc.push(Ok(output.to_repl(self.type_context))),
acc.push(Ok(output.to_repl(self.type_context))),
Ok(_) => (), Ok(_) => (),
Err(error) => { Err(error) => {
acc.push(Err(error.msg)); acc.push(Err(error.msg));
@ -57,47 +38,25 @@ impl<'a, 'b> Evaluator<'a, 'b> {
fn block(&mut self, statements: Vec<Statement>) -> EvalResult<Primitive> { fn block(&mut self, statements: Vec<Statement>) -> EvalResult<Primitive> {
//TODO need to handle breaks, returns, etc. //TODO need to handle breaks, returns, etc.
let mut retval = None; let mut ret = None;
for stmt in statements.into_iter() { for stmt in statements.into_iter() {
match self.statement(stmt)? { if let Some(MemoryValue::Primitive(prim)) = self.statement(stmt)? {
StatementOutput::Nothing => (), ret = Some(prim);
StatementOutput::Primitive(prim) => {
retval = Some(prim);
}
};
if self.early_returning {
break;
}
if let Some(_) = self.loop_control {
break;
} }
} }
Ok(if let Some(ret) = retval { ret } else { self.expression(Expression::unit())? }) Ok(if let Some(ret) = ret { ret } else { self.expression(Expression::unit())? })
} }
fn statement(&mut self, stmt: Statement) -> EvalResult<StatementOutput> { fn statement(&mut self, stmt: Statement) -> EvalResult<Option<MemoryValue>> {
match stmt { match stmt {
Statement::Binding { ref id, expr, constant: _ } => { Statement::Binding { ref id, expr, constant: _ } => {
let evaluated = self.expression(expr)?; let evaluated = self.expression(expr)?;
self.state.environments.insert(id.into(), evaluated.into()); self.state.environments.insert(id.into(), evaluated.into());
Ok(StatementOutput::Nothing) Ok(None)
} }
Statement::Expression(expr) => { Statement::Expression(expr) => {
let evaluated = self.expression(expr)?; let evaluated = self.expression(expr)?;
Ok(StatementOutput::Primitive(evaluated)) Ok(Some(evaluated.into()))
}
Statement::Return(expr) => {
let evaluated = self.expression(expr)?;
self.early_returning = true;
Ok(StatementOutput::Primitive(evaluated))
}
Statement::Break => {
self.loop_control = Some(LoopControlFlow::Break);
Ok(StatementOutput::Nothing)
}
Statement::Continue => {
self.loop_control = Some(LoopControlFlow::Continue);
Ok(StatementOutput::Nothing)
} }
} }
} }
@ -165,7 +124,6 @@ impl<'a, 'b> Evaluator<'a, 'b> {
} }
Expression::CaseMatch { box cond, alternatives } => Expression::CaseMatch { box cond, alternatives } =>
self.case_match_expression(cond, alternatives)?, self.case_match_expression(cond, alternatives)?,
Expression::Loop { box cond, statements } => self.loop_expression(cond, statements)?,
Expression::ReductionError(e) => return Err(e.into()), Expression::ReductionError(e) => return Err(e.into()),
Expression::Access { name, box expr } => { Expression::Access { name, box expr } => {
let expr = self.expression(expr)?; let expr = self.expression(expr)?;
@ -192,37 +150,6 @@ impl<'a, 'b> Evaluator<'a, 'b> {
}) })
} }
fn loop_expression(&mut self, cond: Expression, statements: Vec<Statement>) -> EvalResult<Primitive> {
let existing = self.loop_control;
let output = self.loop_expression_inner(cond, statements);
self.loop_control = existing;
output
}
fn loop_expression_inner(
&mut self,
cond: Expression,
statements: Vec<Statement>,
) -> EvalResult<Primitive> {
loop {
let cond = self.expression(cond.clone())?;
match cond {
Primitive::Literal(Literal::Bool(true)) => (),
Primitive::Literal(Literal::Bool(false)) => break,
e => return Err(format!("Loop condition evaluates to non-boolean: {:?}", e).into()),
};
//TODO eventually loops shoudl be able to return something
let _output = self.block(statements.clone())?;
match self.loop_control {
None | Some(LoopControlFlow::Continue) => (),
Some(LoopControlFlow::Break) => {
break;
}
}
}
Ok(Primitive::unit())
}
fn case_match_expression( fn case_match_expression(
&mut self, &mut self,
cond: Expression, cond: Expression,
@ -261,20 +188,6 @@ impl<'a, 'b> Evaluator<'a, 'b> {
_ => false, _ => false,
}, },
}, },
Pattern::Record { tag: pattern_tag, subpatterns } => match scrut {
//TODO several types of possible error here
Primitive::Object { tag, items, ordered_fields: Some(ordered_fields), .. }
if tag == pattern_tag =>
subpatterns.iter().all(|(field_name, subpat)| {
let idx = ordered_fields
.iter()
.position(|field| field.as_str() == field_name.as_ref())
.unwrap();
let item = &items[idx];
matches(item, subpat, scope)
}),
_ => false,
},
} }
} }
let cond = self.expression(cond)?; let cond = self.expression(cond)?;
@ -283,10 +196,9 @@ impl<'a, 'b> Evaluator<'a, 'b> {
let mut new_scope = self.state.environments.new_scope(None); let mut new_scope = self.state.environments.new_scope(None);
if matches(&cond, &alt.pattern, &mut new_scope) { if matches(&cond, &alt.pattern, &mut new_scope) {
let mut new_state = State { environments: new_scope }; let mut new_state = State { environments: new_scope };
let mut evaluator = Evaluator::new(&mut new_state, self.type_context); let mut evaluator = Evaluator { state: &mut new_state, type_context: self.type_context };
let output = evaluator.block(alt.item);
self.early_returning = evaluator.early_returning; return evaluator.block(alt.item);
return output;
} }
} }
Err("No valid match in match expression".into()) Err("No valid match in match expression".into())
@ -407,12 +319,6 @@ impl<'a, 'b> Evaluator<'a, 'b> {
(Equality, Lit(Bool(l)), Lit(Bool(r))) => Bool(l == r).into(), (Equality, Lit(Bool(l)), Lit(Bool(r))) => Bool(l == r).into(),
(Equality, Lit(StringLit(ref l)), Lit(StringLit(ref r))) => Bool(l == r).into(), (Equality, Lit(StringLit(ref l)), Lit(StringLit(ref r))) => Bool(l == r).into(),
(NotEqual, Lit(Nat(l)), Lit(Nat(r))) => Bool(l != r).into(),
(NotEqual, Lit(Int(l)), Lit(Int(r))) => Bool(l != r).into(),
(NotEqual, Lit(Float(l)), Lit(Float(r))) => Bool(l != r).into(),
(NotEqual, Lit(Bool(l)), Lit(Bool(r))) => Bool(l != r).into(),
(NotEqual, Lit(StringLit(ref l)), Lit(StringLit(ref r))) => Bool(l != r).into(),
(LessThan, Lit(Nat(l)), Lit(Nat(r))) => Bool(l < r).into(), (LessThan, Lit(Nat(l)), Lit(Nat(r))) => Bool(l < r).into(),
(LessThan, Lit(Int(l)), Lit(Int(r))) => Bool(l < r).into(), (LessThan, Lit(Int(l)), Lit(Int(r))) => Bool(l < r).into(),
(LessThan, Lit(Float(l)), Lit(Float(r))) => Bool(l < r).into(), (LessThan, Lit(Float(l)), Lit(Float(r))) => Bool(l < r).into(),
@ -454,7 +360,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
} }
let mut frame_state = State { environments: self.state.environments.new_scope(None) }; let mut frame_state = State { environments: self.state.environments.new_scope(None) };
let mut evaluator = Evaluator::new(&mut frame_state, self.type_context); let mut evaluator = Evaluator { state: &mut frame_state, type_context: self.type_context };
for (n, evaled) in evaluated_args.into_iter().enumerate() { for (n, evaled) in evaluated_args.into_iter().enumerate() {
let n = n as u8; let n = n as u8;

View File

@ -88,6 +88,15 @@ impl From<Primitive> for MemoryValue {
} }
} }
impl MemoryValue {
fn to_repl(&self, type_context: &TypeContext) -> String {
match self {
MemoryValue::Primitive(ref prim) => prim.to_repl(type_context),
MemoryValue::Function(..) => "<function>".to_string(),
}
}
}
#[derive(Debug)] #[derive(Debug)]
enum RuntimeValue { enum RuntimeValue {
Expression(Expression), Expression(Expression),
@ -172,7 +181,7 @@ impl<'a> State<'a> {
type_context: &TypeContext, type_context: &TypeContext,
repl: bool, repl: bool,
) -> Vec<Result<String, String>> { ) -> Vec<Result<String, String>> {
let mut evaluator = evaluator::Evaluator::new(self, type_context); let mut evaluator = evaluator::Evaluator { state: self, type_context };
evaluator.evaluate(reduced, repl) evaluator.evaluate(reduced, repl)
} }
} }

View File

@ -21,7 +21,7 @@ fn evaluate_input(input: &str) -> Result<String, String> {
symbol_table.debug(); symbol_table.debug();
let mut state = State::new(); let mut state = State::new();
let mut evaluator = Evaluator::new(&mut state, &type_context); let mut evaluator = Evaluator { state: &mut state, type_context: &type_context };
let mut outputs = evaluator.evaluate(reduced_ir, true); let mut outputs = evaluator.evaluate(reduced_ir, true);
outputs.pop().unwrap() outputs.pop().unwrap()
} }
@ -172,29 +172,6 @@ if x {
eval_assert(&source, expected); eval_assert(&source, expected);
} }
#[test]
fn record_patterns() {
let source = r#"
type Ara = Kueh { a: Int, b: String } | Morbuk
let alpha = Ara::Kueh { a: 10, b: "sanchez" }
if alpha {
is Ara::Kueh { a, b } then (b, a)
is _ then ("nooo", 8888)
}"#;
eval_assert(source, r#"("sanchez", 10)"#);
let source = r#"
type Ara = Kueh { a: Int, b: String } | Morbuk
let alpha = Ara::Kueh { a: 10, b: "sanchez" }
if alpha {
is Ara::Kueh { a, b: le_value } then (le_value, (a*2))
is _ then ("nooo", 8888)
}"#;
eval_assert(source, r#"("sanchez", 20)"#);
}
#[test] #[test]
fn if_is_patterns() { fn if_is_patterns() {
let source = r#" let source = r#"
@ -401,53 +378,3 @@ let value = Klewos::Klewos { a: 50, b: "nah" }
eval_assert(source, r#"(50, "nah")"#); eval_assert(source, r#"(50, "nah")"#);
} }
#[test]
fn early_return() {
let source = r#"
fn chnurmek(a: Int): Int {
if a == 5 then {
return 9999;
}
return (a + 2);
}
(chnurmek(5), chnurmek(0))
"#;
eval_assert(source, r#"(9999, 2)"#);
let source = r#"
fn marbuk(a: Int, b: Int): (Int, Int) {
if a == 5 then {
if b == 6 then {
return (50, 50);
}
return (a, b + 1)
}
(a * 100, b * 100)
}
let x = marbuk(1, 1)
let y = marbuk(5, 1)
let z = marbuk(5, 6)
(x, y, z)
"#;
eval_assert(source, "((100, 100), (5, 2), (50, 50))");
}
#[test]
fn loops() {
let source = r#"
let mut a = 0
let mut count = 0
while a != 5 {
a = a + 1
count = count + 100
}
count
"#;
eval_assert(source, "500");
}