Compare commits
5 Commits
7766a8ae30
...
64b8d18fe8
Author | SHA1 | Date |
---|---|---|
Emi Simpson | 64b8d18fe8 | |
Emi Simpson | 780ada7034 | |
Emi Simpson | 1895364870 | |
Emi Simpson | 2134e96498 | |
Emi Simpson | d298170022 |
|
@ -1,5 +1,8 @@
|
|||
cool_number: Int
|
||||
cool_number = 1312
|
||||
|
||||
main: Int
|
||||
main = nth_prime 77
|
||||
main = nth_prime cool_number
|
||||
|
||||
nth_prime: Int -> Int
|
||||
nth_prime n =
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
use std::{collections::{HashMap, LinkedList}, mem::Discriminant};
|
||||
|
||||
use super::{Identifier, value::Value, expr::Operation, types::Type};
|
||||
use super::{Identifier, value::Value, expr::Operation, types::{Type, PrimitiveType}, Declaration};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct ValueBindings<'a>(Option<&'a ValueBindings<'a>>, HashMap<u128, Value>);
|
||||
|
||||
impl<'a> ValueBindings<'a> {
|
||||
pub fn builtins() -> Self {
|
||||
Self::default()
|
||||
.bind(&Identifier::identifier_Int(), Value::Type(Type::Primitive(PrimitiveType::Int)))
|
||||
}
|
||||
|
||||
pub fn bind(mut self, ident: &Identifier, value: Value) -> Self {
|
||||
self.1.insert(ident.1 as u128, value);
|
||||
self
|
||||
|
@ -19,6 +24,14 @@ impl<'a> ValueBindings<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn bind_all_owned(mut self, other: LinkedList<(Identifier, Value)>) -> Self{
|
||||
self.1.extend(
|
||||
other.into_iter()
|
||||
.map(|(ident, val)| (ident.1 as u128, val))
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn lookup(&self, ident: &Identifier) -> Option<&Value> {
|
||||
self.1.get(&(ident.1 as u128))
|
||||
.or_else(|| self.0.and_then(|binding| binding.lookup(ident)))
|
||||
|
@ -45,3 +58,38 @@ pub enum EvaluateError {
|
|||
}
|
||||
|
||||
pub type Result = std::result::Result<Value, EvaluateError>;
|
||||
|
||||
pub fn display_program(program: Vec<Declaration>) -> std::result::Result<String, EvaluateError> {
|
||||
let bindings = ValueBindings::builtins();
|
||||
let bindings = program.iter()
|
||||
.fold(bindings, |bindings, declaration|
|
||||
bindings.bind(&declaration.identifier, declaration.value.clone())
|
||||
);
|
||||
|
||||
program.into_iter()
|
||||
.map(|decl| {
|
||||
Ok(match decl.value.simplify(&bindings)? {
|
||||
Value::Function(args, val) => {
|
||||
format!(
|
||||
"{0} has type {1}\n{0} takes the arguments: {2}\n",
|
||||
decl.identifier,
|
||||
decl.value_type.simplify(&bindings)?,
|
||||
args.into_iter()
|
||||
.map(|arg| arg.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
)
|
||||
}
|
||||
other => {
|
||||
format!(
|
||||
"{0} has type {1}\n{0} has the value {2}\n",
|
||||
decl.identifier,
|
||||
decl.value_type.simplify(&bindings)?,
|
||||
other,
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect::<std::result::Result<Vec<_>, _>>()
|
||||
.map(|lines| lines.join("\n"))
|
||||
}
|
||||
|
|
175
src/ir/expr.rs
175
src/ir/expr.rs
|
@ -1,7 +1,7 @@
|
|||
use core::fmt;
|
||||
use std::{collections::{LinkedList, HashSet}, mem::{self, discriminant}};
|
||||
use std::{collections::{LinkedList, HashSet}, mem::{self, discriminant}, borrow::Cow, ops::FromResidual, convert::Infallible};
|
||||
|
||||
use super::{value::Value, pattern::Pattern, Identifier, evaluation::{ValueBindings, self, EvaluateError}};
|
||||
use super::{value::Value, pattern::Pattern, Identifier, evaluation::{ValueBindings, self, EvaluateError}, types::{PrimitiveType, Type}};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Expr {
|
||||
|
@ -10,6 +10,30 @@ pub struct Expr {
|
|||
pub formals: Vec<Identifier>,
|
||||
}
|
||||
|
||||
pub enum ExprEvalResult<'a> {
|
||||
Succeeded(Value),
|
||||
EvaluateThis(&'a LinkedList<Expr>, LinkedList<(&'a Identifier, &'a Value)>),
|
||||
Failed(EvaluateError),
|
||||
}
|
||||
|
||||
impl From<evaluation::Result> for ExprEvalResult<'_> {
|
||||
fn from(res: evaluation::Result) -> Self {
|
||||
match res {
|
||||
Ok(v) => Self::Succeeded(v),
|
||||
Err(e) => Self::Failed(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromResidual<Result<Infallible, EvaluateError>> for ExprEvalResult<'_> {
|
||||
fn from_residual(residual: Result<Infallible, EvaluateError>) -> Self {
|
||||
match residual {
|
||||
Err(e) => Self::Failed(e),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
pub fn isnt_noop(&self) -> bool {
|
||||
if let Operation::NoOp = self.operation {
|
||||
|
@ -18,17 +42,18 @@ impl Expr {
|
|||
true
|
||||
}
|
||||
}
|
||||
pub fn evaluate(&self, bindings: &ValueBindings) -> evaluation::Result {
|
||||
pub fn evaluate<'a>(&'a self, bindings: &'a ValueBindings) -> ExprEvalResult<'a> {
|
||||
let arguments = self.formals
|
||||
.iter()
|
||||
.map(|formal| bindings.lookup(formal).cloned().ok_or_else(|| EvaluateError::UndefinedValue(formal.clone())))
|
||||
.map(|formal| bindings.lookup(formal).ok_or_else(|| EvaluateError::UndefinedValue(formal.clone())))
|
||||
.collect::<Result<Vec<_>, EvaluateError>>()?;
|
||||
match &self.operation {
|
||||
Operation::Add =>
|
||||
arguments.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.try_fold(0, |a, b| b.map(|b: usize| a + b))
|
||||
.map(Value::Int),
|
||||
.map(Value::Int)
|
||||
.into(),
|
||||
Operation::Sub => {
|
||||
let mut args = arguments.into_iter()
|
||||
.map(TryInto::try_into);
|
||||
|
@ -37,13 +62,15 @@ impl Expr {
|
|||
.and_then(std::convert::identity)?;
|
||||
args.try_fold(first_arg, |a, b| b.map(|b| a - b))
|
||||
.map(Value::Int)
|
||||
.into()
|
||||
}
|
||||
|
||||
Operation::Mul =>
|
||||
arguments.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.try_fold(1, |a, b| b.map(|b: usize| a * b))
|
||||
.map(Value::Int),
|
||||
.map(Value::Int)
|
||||
.into(),
|
||||
Operation::Div => {
|
||||
let mut args = arguments.into_iter()
|
||||
.map(TryInto::try_into);
|
||||
|
@ -52,6 +79,7 @@ impl Expr {
|
|||
.and_then(std::convert::identity)?;
|
||||
args.try_fold(first_arg, |a, b| b.map(|b| a / b))
|
||||
.map(Value::Int)
|
||||
.into()
|
||||
}
|
||||
Operation::Mod => {
|
||||
let mut args = arguments.into_iter()
|
||||
|
@ -61,6 +89,7 @@ impl Expr {
|
|||
.and_then(std::convert::identity)?;
|
||||
args.try_fold(first_arg, |a, b| b.map(|b| a % b))
|
||||
.map(Value::Int)
|
||||
.into()
|
||||
}
|
||||
Operation::Range => todo!(),
|
||||
Operation::Eq =>
|
||||
|
@ -77,14 +106,15 @@ impl Expr {
|
|||
}, Some(to_compare))
|
||||
)
|
||||
)
|
||||
.map(|(result, _)| if result { Value::Int(1) } else { Value::Int(0) }),
|
||||
.map(|(result, _)| if result { Value::Int(1) } else { Value::Int(0) })
|
||||
.into(),
|
||||
Operation::NEq =>
|
||||
if
|
||||
ExprEvalResult::Succeeded(if
|
||||
arguments.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<HashSet<usize>, EvaluateError>>()?
|
||||
.len() == self.formals.len()
|
||||
{ Ok(Value::Int(1)) } else { Ok(Value::Int(2)) },
|
||||
{ Value::Int(1) } else { Value::Int(2) }),
|
||||
Operation::LessThan =>
|
||||
arguments.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
|
@ -97,7 +127,8 @@ impl Expr {
|
|||
), Some(to_compare))
|
||||
)
|
||||
)
|
||||
.map(|(result, _)| if result { Value::Int(1) } else { Value::Int(0) }),
|
||||
.map(|(result, _)| if result { Value::Int(1) } else { Value::Int(0) })
|
||||
.into(),
|
||||
Operation::GreaterThan =>
|
||||
arguments.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
|
@ -110,18 +141,21 @@ impl Expr {
|
|||
), Some(to_compare))
|
||||
)
|
||||
)
|
||||
.map(|(result, _)| if result { Value::Int(1) } else { Value::Int(0) }),
|
||||
.map(|(result, _)| if result { Value::Int(1) } else { Value::Int(0) })
|
||||
.into(),
|
||||
Operation::LAnd =>
|
||||
arguments.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.try_fold(true, |a, b| b.map(|b: bool| a && b))
|
||||
.map(|result| if result { Value::Int(1) } else { Value::Int(0) }),
|
||||
.map(|result| if result { Value::Int(1) } else { Value::Int(0) })
|
||||
.into(),
|
||||
Operation::LOr =>
|
||||
arguments.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.try_fold(true, |a, b| b.map(|b: bool| a || b))
|
||||
.map(|result| if result { Value::Int(1) } else { Value::Int(0) }),
|
||||
Operation::Const(v) => Ok(v.clone()),
|
||||
.map(|result| if result { Value::Int(1) } else { Value::Int(0) })
|
||||
.into(),
|
||||
Operation::Const(v) => ExprEvalResult::Succeeded(v.clone()),
|
||||
Operation::Call => {
|
||||
let mut args = arguments.into_iter();
|
||||
let first_arg = args.next()
|
||||
|
@ -129,21 +163,18 @@ impl Expr {
|
|||
match first_arg {
|
||||
Value::Function(formals, code) => {
|
||||
if formals.len() == args.size_hint().0 {
|
||||
let new_scope = bindings.nested_scope();
|
||||
let bound_scope = formals.into_iter()
|
||||
let bindings = formals.into_iter()
|
||||
.zip(args)
|
||||
.fold(
|
||||
new_scope,
|
||||
|scope, (formal, value)|
|
||||
scope.bind(&formal, value)
|
||||
);
|
||||
evaluate(code, &bound_scope)
|
||||
.collect();
|
||||
ExprEvalResult::EvaluateThis(code, bindings)
|
||||
} else {
|
||||
Err(EvaluateError::FunctionArgumentCountMismatch(args.size_hint().0, formals.len()))
|
||||
ExprEvalResult::Failed(
|
||||
EvaluateError::FunctionArgumentCountMismatch(args.size_hint().0, formals.len())
|
||||
)
|
||||
}
|
||||
},
|
||||
first_arg @ _ => {
|
||||
Err(EvaluateError::TypeMismatch(
|
||||
ExprEvalResult::Failed(EvaluateError::TypeMismatch(
|
||||
discriminant(&first_arg),
|
||||
discriminant(&Value::Function(Vec::new(), LinkedList::new())),
|
||||
))
|
||||
|
@ -151,8 +182,28 @@ impl Expr {
|
|||
}
|
||||
}
|
||||
Operation::VariantUnion => todo!(),
|
||||
Operation::FunctionType => todo!(),
|
||||
Operation::NoOp => Ok(Value::Int(0)),
|
||||
Operation::FunctionType => {
|
||||
if let [a, b] = arguments[..] {
|
||||
if let (Value::Type(a), Value::Type(b)) = (a, b) {
|
||||
ExprEvalResult::Succeeded(Value::Type(Type::Function(Box::new(a.clone()), Box::new(b.clone()))))
|
||||
} else {
|
||||
ExprEvalResult::Failed(EvaluateError::TypeMismatch(discriminant(b), discriminant(&Value::Type(Type::Primitive(PrimitiveType::Int)))))
|
||||
}
|
||||
} else {
|
||||
ExprEvalResult::Failed(EvaluateError::ArgumentCountMismatch(Operation::FunctionType, arguments.len(), 2))
|
||||
}
|
||||
},
|
||||
Operation::NoOp => {
|
||||
// Look up the value, if it's a zero-arg function, evaluate it
|
||||
let apparent_value =
|
||||
bindings.lookup(&self.identifier)
|
||||
.ok_or_else(|| EvaluateError::UndefinedValue(self.identifier.clone()))?;
|
||||
match apparent_value {
|
||||
Value::Function(args, exprs) if args.is_empty() =>
|
||||
ExprEvalResult::EvaluateThis(exprs, LinkedList::new()),
|
||||
val => ExprEvalResult::Succeeded(val.clone()),
|
||||
}
|
||||
}
|
||||
Operation::Conditional(cases) => {
|
||||
let mut arguments = arguments;
|
||||
let value =
|
||||
|
@ -160,16 +211,14 @@ impl Expr {
|
|||
let (new_bindings, code) = cases.into_iter()
|
||||
.find_map(|(pattern, code)| pattern.matches(&value).map(|bindings| (bindings, code)))
|
||||
.ok_or(EvaluateError::IncompleteConditional)?;
|
||||
let local_scope = bindings.nested_scope()
|
||||
.bind_all(new_bindings);
|
||||
evaluate(code.clone(), &local_scope)
|
||||
ExprEvalResult::EvaluateThis(code, new_bindings)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Expr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Operation::NoOp = self.operation {
|
||||
self.identifier.fmt(f)
|
||||
} else {
|
||||
|
@ -182,7 +231,7 @@ impl fmt::Display for Expr {
|
|||
.collect::<String>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -208,7 +257,7 @@ pub enum Operation {
|
|||
}
|
||||
|
||||
impl fmt::Debug for Operation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
Self::Add => "plus",
|
||||
Self::Sub => "minus",
|
||||
|
@ -233,7 +282,7 @@ impl fmt::Debug for Operation {
|
|||
return write!(f, "cond({branches:?})");
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_last_ident_name(mut exprs: LinkedList<Expr>, name: String) -> LinkedList<Expr> {
|
||||
|
@ -250,31 +299,39 @@ pub fn get_last_ident(exprs: &LinkedList<Expr>) -> Option<Identifier> {
|
|||
exprs.back().map(|expr| expr.identifier.clone())
|
||||
}
|
||||
|
||||
pub fn evaluate(exprs: LinkedList<Expr>, bindings: &ValueBindings) -> evaluation::Result {
|
||||
if exprs.iter().all(|e| !e.isnt_noop()) {
|
||||
bindings.lookup(&exprs.back().ok_or(EvaluateError::EvaluatingZeroLengthExpr)?.identifier)
|
||||
.ok_or_else(|| EvaluateError::UndefinedValue(exprs.back().unwrap().identifier.clone()))
|
||||
.cloned()
|
||||
} else if exprs.len() == 1 {
|
||||
exprs.back()
|
||||
.unwrap()
|
||||
.evaluate(&bindings)
|
||||
pub fn evaluate(mut exprs: LinkedList<Expr>, mut bindings: ValueBindings) -> evaluation::Result { loop { return
|
||||
if exprs.len() == 1 {
|
||||
let instr = exprs.back().unwrap();
|
||||
let res = instr.evaluate(&bindings);
|
||||
match res {
|
||||
ExprEvalResult::Succeeded(v) => Ok(v),
|
||||
ExprEvalResult::EvaluateThis(code, new_bindings) => {
|
||||
let code = code.clone();
|
||||
let new_bindings = new_bindings.into_iter()
|
||||
.map(|(ident, val)| (ident.clone(), val.clone()))
|
||||
.collect();
|
||||
|
||||
exprs = code;
|
||||
bindings = bindings.bind_all_owned(new_bindings);
|
||||
continue; // Tail-recursive "call"
|
||||
}
|
||||
ExprEvalResult::Failed(e) => Err(e),
|
||||
}
|
||||
} else {
|
||||
let bindings = bindings.nested_scope();
|
||||
let (all_bindings, last_ident) = exprs.into_iter()
|
||||
.filter(Expr::isnt_noop)
|
||||
.try_fold(
|
||||
(bindings, None),
|
||||
|(bindings, _last_ident), expr| {
|
||||
let last_value = expr.evaluate(&bindings)?;
|
||||
Ok((bindings.bind(&expr.identifier, last_value.clone()), Some(expr.identifier)))
|
||||
})?;
|
||||
last_ident.ok_or(EvaluateError::EvaluatingZeroLengthExpr)
|
||||
.and_then(
|
||||
|ident|
|
||||
all_bindings.lookup(&ident)
|
||||
.cloned()
|
||||
.ok_or(EvaluateError::UndefinedValue(ident))
|
||||
)
|
||||
let first_instruction = exprs.pop_front().ok_or(EvaluateError::EvaluatingZeroLengthExpr)?;
|
||||
let res = first_instruction.evaluate(&bindings);
|
||||
let res_value = match res {
|
||||
ExprEvalResult::Succeeded(v) => v,
|
||||
ExprEvalResult::EvaluateThis(code, new_bindings) => {
|
||||
let local_scope = bindings.nested_scope()
|
||||
.bind_all(new_bindings);
|
||||
evaluate(code.clone(), local_scope)?
|
||||
},
|
||||
ExprEvalResult::Failed(e) => return Err(e),
|
||||
};
|
||||
|
||||
exprs = exprs;
|
||||
bindings = bindings.bind(&first_instruction.identifier, res_value);
|
||||
continue; // Tail-recursive "call"
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -41,6 +41,11 @@ impl Identifier {
|
|||
pub fn set_name(self, new_name: String) -> Identifier {
|
||||
Identifier(new_name, self.1, self.2)
|
||||
}
|
||||
|
||||
pub fn identifier_Int() -> Identifier {
|
||||
Identifier::main()
|
||||
.subid_with_name("Int".to_string(), 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Identifier {
|
||||
|
@ -85,7 +90,7 @@ pub fn is_prime(x: usize, known_primes: &[usize]) -> bool {
|
|||
#[derive(Debug)]
|
||||
pub struct Declaration {
|
||||
pub identifier: Identifier,
|
||||
pub value_type: Type,
|
||||
pub value_type: Value,
|
||||
pub value: Value,
|
||||
}
|
||||
|
||||
|
@ -100,33 +105,16 @@ impl fmt::Display for Declaration {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn hasty_evaluate(program: Vec<Declaration>) -> evaluation::Result {
|
||||
let bindings = ValueBindings::default();
|
||||
let bindings = program.into_iter()
|
||||
.fold(bindings, |bindings, declaration|
|
||||
bindings.bind(&declaration.identifier, declaration.value)
|
||||
);
|
||||
if let Some(main) = bindings.get_main() {
|
||||
if let Value::Function(args, code) = main {
|
||||
if args.is_empty() {
|
||||
evaluate(code.clone(), &bindings)
|
||||
} else {
|
||||
Err(EvaluateError::MainHasArgs)
|
||||
}
|
||||
} else {
|
||||
Ok(main.clone())
|
||||
}
|
||||
} else {
|
||||
Err(EvaluateError::NoMain)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BindingScope<'a>(Option<&'a BindingScope<'a>>, Vec<Identifier>);
|
||||
|
||||
impl<'a> BindingScope<'a> {
|
||||
pub const ROOT: BindingScope<'static> = BindingScope(None, Vec::new());
|
||||
|
||||
pub fn builtins() -> BindingScope<'static> {
|
||||
BindingScope::ROOT.bind_single(Identifier::identifier_Int())
|
||||
}
|
||||
|
||||
pub fn bind(&self, idents: Vec<Identifier>) -> BindingScope {
|
||||
BindingScope(Some(self), idents)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use core::fmt;
|
|||
|
||||
use super::Identifier;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Variant {
|
||||
pub name: Identifier,
|
||||
pub elements: Vec<Type>,
|
||||
|
@ -21,10 +21,10 @@ impl fmt::Display for Variant {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Type {
|
||||
UserDefined(Vec<Variant>),
|
||||
Function(Vec<Type>, Box<Type>),
|
||||
Function(Box<Type>, Box<Type>),
|
||||
Primitive(PrimitiveType),
|
||||
}
|
||||
|
||||
|
@ -42,10 +42,7 @@ impl fmt::Display for Type {
|
|||
Self::Function(args, return_type) =>
|
||||
write!(f,
|
||||
"{} -> {}",
|
||||
args.into_iter()
|
||||
.map(ToString::to_string)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" , "),
|
||||
args,
|
||||
return_type
|
||||
),
|
||||
Self::Primitive(p) => p.fmt(f),
|
||||
|
@ -53,7 +50,7 @@ impl fmt::Display for Type {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub enum PrimitiveType {
|
||||
Int,
|
||||
Str,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use core::fmt;
|
||||
use std::{collections::LinkedList, mem::discriminant};
|
||||
|
||||
use super::{expr::Expr, Identifier, evaluation::EvaluateError};
|
||||
use super::{expr::{Expr, evaluate}, Identifier, evaluation::{EvaluateError, ValueBindings, self}, types::Type};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Value {
|
||||
|
@ -9,6 +9,18 @@ pub enum Value {
|
|||
String(String),
|
||||
Function(Vec<Identifier>, LinkedList<Expr>),
|
||||
Structural(Identifier, Vec<Value>),
|
||||
Type(Type),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
/// Converts a zero-arg function into its result
|
||||
pub fn simplify(self, bindings: &ValueBindings) -> evaluation::Result {
|
||||
match self {
|
||||
Value::Function(args, value) if args.is_empty() =>
|
||||
evaluate(value, bindings.nested_scope()),
|
||||
other => Ok(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Value {
|
||||
|
@ -27,16 +39,17 @@ impl fmt::Display for Value {
|
|||
.collect::<String>(),
|
||||
),
|
||||
Self::Structural(_, _) => todo!(),
|
||||
Self::Type(typ) => typ.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryInto<usize> for Value {
|
||||
impl TryInto<usize> for &Value {
|
||||
type Error = EvaluateError;
|
||||
|
||||
fn try_into(self) -> Result<usize, EvaluateError> {
|
||||
if let Value::Int(v) = self {
|
||||
Ok(v)
|
||||
Ok(*v)
|
||||
} else {
|
||||
Err(EvaluateError::TypeMismatch(
|
||||
discriminant(&Value::Int(0)),
|
||||
|
@ -46,12 +59,12 @@ impl TryInto<usize> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryInto<bool> for Value {
|
||||
impl TryInto<bool> for &Value {
|
||||
type Error = EvaluateError;
|
||||
|
||||
fn try_into(self) -> Result<bool, EvaluateError> {
|
||||
if let Value::Int(v) = self {
|
||||
Ok(v != 0)
|
||||
Ok(*v != 0)
|
||||
} else {
|
||||
Err(EvaluateError::TypeMismatch(
|
||||
discriminant(&Value::Int(0)),
|
||||
|
|
70
src/main.rs
70
src/main.rs
|
@ -1,16 +1,18 @@
|
|||
#![feature(try_trait_v2)]
|
||||
|
||||
use std::{fs::File, io::Read, collections::LinkedList, process::exit};
|
||||
|
||||
use logos::Logos;
|
||||
use parser::{program::Program, Parsable, WrappedLexer};
|
||||
|
||||
use crate::ir::{hasty_evaluate, evaluation::EvaluateError};
|
||||
use crate::ir::evaluation::{EvaluateError, display_program};
|
||||
|
||||
mod token;
|
||||
mod parser;
|
||||
mod ir;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let mut input_file = File::open("sample-initial.amo")?;
|
||||
let mut input_file = std::io::stdin();
|
||||
let mut input = String::with_capacity(4096);
|
||||
input_file.read_to_string(&mut input)?;
|
||||
|
||||
|
@ -29,43 +31,37 @@ fn main() -> std::io::Result<()> {
|
|||
Ok(p) => p
|
||||
};
|
||||
|
||||
println!("Parse successful!!");
|
||||
for decl in &program.0 {
|
||||
println!("{decl:?}\n");
|
||||
}
|
||||
println!("Parse successful! Building IR...");
|
||||
|
||||
println!("Building IR...");
|
||||
match program.gen_ir() {
|
||||
Ok(program) => {
|
||||
println!(
|
||||
"IR built successfully!\n{}",
|
||||
program.iter()
|
||||
.map(|decl| format!("\n\n{decl}\n\n"))
|
||||
.collect::<String>(),
|
||||
);
|
||||
match hasty_evaluate(program) {
|
||||
Ok(value) =>
|
||||
println!("Evaluated successfully! Got: {value}"),
|
||||
Err(EvaluateError::UndefinedValue(v)) =>
|
||||
println!("Hit an error: {v} is undefined"),
|
||||
Err(EvaluateError::EvaluatingZeroLengthExpr) =>
|
||||
println!("Hit an error: Tried to evaluate a series of zero instructions"),
|
||||
Err(EvaluateError::ArgumentCountMismatch(op, real, ex)) =>
|
||||
println!("Problem while evaluating operation {op:?}: expected {ex} arguments, got {real}"),
|
||||
Err(EvaluateError::FunctionArgumentCountMismatch(real, ex)) =>
|
||||
println!("Problem while evaluating a function: expected {ex} arguments, got {real}"),
|
||||
Err(EvaluateError::TypeMismatch(a, b)) =>
|
||||
println!("Type mismatch between {a:?} and {b:?}!"),
|
||||
Err(EvaluateError::NoMain) =>
|
||||
println!("Huh, there's no main method"),
|
||||
Err(EvaluateError::MainHasArgs) =>
|
||||
println!("Your main method has args, but that's not allowed"),
|
||||
Err(EvaluateError::IncompleteConditional) =>
|
||||
println!("Uh oh, a conditional somewhere isn't complete!"),
|
||||
}
|
||||
let program = match program.gen_ir() {
|
||||
Ok(program) => program,
|
||||
Err(e) => {
|
||||
println!("Oh noes! {e:?}");
|
||||
exit(2);
|
||||
}
|
||||
Err(e) =>
|
||||
println!("Oh noes! {e:?}"),
|
||||
};
|
||||
|
||||
println!("IR built successfully! Evaluating...");
|
||||
|
||||
match display_program(program) {
|
||||
Ok(value) =>
|
||||
println!("Evaluated successfully!\n\n{value}"),
|
||||
Err(EvaluateError::UndefinedValue(v)) =>
|
||||
println!("Hit an error: {v} is undefined"),
|
||||
Err(EvaluateError::EvaluatingZeroLengthExpr) =>
|
||||
println!("Hit an error: Tried to evaluate a series of zero instructions"),
|
||||
Err(EvaluateError::ArgumentCountMismatch(op, real, ex)) =>
|
||||
println!("Problem while evaluating operation {op:?}: expected {ex} arguments, got {real}"),
|
||||
Err(EvaluateError::FunctionArgumentCountMismatch(real, ex)) =>
|
||||
println!("Problem while evaluating a function: expected {ex} arguments, got {real}"),
|
||||
Err(EvaluateError::TypeMismatch(a, b)) =>
|
||||
println!("Type mismatch between {a:?} and {b:?}!"),
|
||||
Err(EvaluateError::NoMain) =>
|
||||
println!("Huh, there's no main method"),
|
||||
Err(EvaluateError::MainHasArgs) =>
|
||||
println!("Your main method has args, but that's not allowed"),
|
||||
Err(EvaluateError::IncompleteConditional) =>
|
||||
println!("Uh oh, a conditional somewhere isn't complete!"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::mem::{Discriminant, discriminant};
|
||||
|
||||
use crate::{token::Token, ir::{self, IrError, Identifier, BindingScope, types::{Type, PrimitiveType}}};
|
||||
use crate::{token::Token, ir::{self, IrError, Identifier, BindingScope}};
|
||||
|
||||
use super::{Parsable, WrappedLexer, ParseError, absorb_token_or_error, expr::Expr};
|
||||
|
||||
|
@ -63,10 +63,11 @@ impl Declaration {
|
|||
let n_args = args.len() as u32;
|
||||
let local_binding = bindings.bind(args.clone());
|
||||
let expression_dag = value.gen_ir(&local_binding, &own_id, n_args, false)?;
|
||||
let type_dag = type_.gen_ir(&local_binding, &own_id, n_args + 1, true)?;
|
||||
Ok(Some(
|
||||
ir::Declaration {
|
||||
identifier: own_id,
|
||||
value_type: Type::Primitive(PrimitiveType::Int), // TODO
|
||||
value_type: ir::value::Value::Function(Vec::new(), type_dag),
|
||||
value: ir::value::Value::Function(args, expression_dag),
|
||||
}
|
||||
))
|
||||
|
|
|
@ -22,8 +22,12 @@ pub trait GenIR {
|
|||
) -> ir::Result<LinkedList<ir::expr::Expr>>;
|
||||
}
|
||||
|
||||
pub enum Direction { LeftToRight, RightToLeft }
|
||||
pub trait InfixOp {
|
||||
fn gen_ir(&self) -> Operation;
|
||||
fn direction(&self) -> Direction {
|
||||
Direction::LeftToRight
|
||||
}
|
||||
}
|
||||
|
||||
impl InfixOp for InfixRank1 {
|
||||
|
@ -42,6 +46,12 @@ impl InfixOp for InfixRank2 {
|
|||
Self::Aro => Operation::FunctionType,
|
||||
}
|
||||
}
|
||||
fn direction(&self) -> Direction {
|
||||
match self {
|
||||
Self::LAnd => Direction::LeftToRight,
|
||||
Self::Aro => Direction::RightToLeft,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InfixOp for InfixRank3 {
|
||||
|
@ -110,7 +120,19 @@ impl<NextRank: GenIR, Op: InfixOp> GenIR for (LinkedList<Expr>, Vec<(Op, NextRan
|
|||
let (first_arg_exprs, mut ops) = self;
|
||||
if let Some((this_op, second_arg)) = ops.pop() {
|
||||
let this_ident = parent.subid_with_name(String::new(), index);
|
||||
let second_arg_exprs = second_arg.gen_ir(bindings, parent, index + 1, type_context)?;
|
||||
let direction = this_op.direction();
|
||||
let (second_arg_exprs, finish_result):
|
||||
(_, Box<dyn FnOnce(LinkedList<ir::expr::Expr>) -> ir::Result<LinkedList<ir::expr::Expr>>>) =
|
||||
match direction {
|
||||
Direction::LeftToRight => (
|
||||
second_arg.gen_ir(bindings, parent, index + 1, type_context)?,
|
||||
Box::new(|all_exprs| (all_exprs, ops).gen_ir(bindings, parent, index + 2, type_context)),
|
||||
),
|
||||
Direction::RightToLeft => (
|
||||
(second_arg, ops).gen_ir(bindings, parent, index + 1, type_context)?,
|
||||
Box::new(|all_exprs| ir::Result::Ok(all_exprs))
|
||||
),
|
||||
};
|
||||
let op = this_op.gen_ir();
|
||||
let first_arg_ident = get_last_ident(&first_arg_exprs).ok_or(IrError::MissingExpression)?;
|
||||
let second_arg_ident = get_last_ident(&second_arg_exprs).ok_or(IrError::MissingExpression)?;
|
||||
|
@ -125,14 +147,14 @@ impl<NextRank: GenIR, Op: InfixOp> GenIR for (LinkedList<Expr>, Vec<(Op, NextRan
|
|||
};
|
||||
let all_prior_exprs = join(first_arg_exprs, second_arg_exprs);
|
||||
let all_exprs = cons_ll(all_prior_exprs, new_expr);
|
||||
(all_exprs, ops).gen_ir(bindings, parent, index + 2, type_context)
|
||||
finish_result(all_exprs)
|
||||
} else {
|
||||
Ok(first_arg_exprs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//pub type Rank4Exp = (TightExpr, Vec<Rank5Exp>);
|
||||
//pub tsecond_arg.gen_ir(bindings, parent, index + 1, type_context)ype Rank4Exp = (TightExpr, Vec<Rank5Exp>);
|
||||
impl GenIR for Rank7Exp {
|
||||
fn gen_ir(
|
||||
self,
|
||||
|
|
|
@ -39,8 +39,7 @@ impl Program {
|
|||
let root_scope = self.0.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, decl)| decl.get_identifier(&Identifier::ROOT, i as u32))
|
||||
.fold(BindingScope::ROOT, |scope, ident| scope.bind_single(ident));
|
||||
println!("DEBUG {root_scope:?}");
|
||||
.fold(BindingScope::builtins(), |scope, ident| scope.bind_single(ident));
|
||||
self.0.into_iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, decl)| decl.gen_ir(&root_scope, i as u32, Identifier::ROOT).transpose())
|
||||
|
|
Loading…
Reference in New Issue