Compare commits
No commits in common. "4c6a93302d260ffa26f2efd69777336b2040cc42" and "76f7524fdbbefb5446f41229a276fc2b33a9b820" have entirely different histories.
4c6a93302d
...
76f7524fdb
5
TODO.md
5
TODO.md
@ -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
|
||||||
|
@ -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)]
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
|
||||||
)]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -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),
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user