From 9ddbf38ecba12c1271159f8e0e82793fb8bd263b Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Sat, 23 Apr 2022 21:52:30 -0400 Subject: [PATCH] IR generation is (almost) done!!! --- sample-initial.amo | 20 +--- src/ir/expr.rs | 92 ++++++++++++++++ src/ir/mod.rs | 118 ++++++++++++++++++++ src/ir/pattern.rs | 10 ++ src/ir/types.rs | 73 +++++++++++++ src/ir/value.rs | 32 ++++++ src/main.rs | 20 +++- src/parser/declaration.rs | 31 +++++- src/parser/expr.rs | 90 ++++++++++++++- src/parser/infix.rs | 223 +++++++++++++++++++++++++++++++++++++- src/parser/mod.rs | 41 +++---- src/parser/pattern.rs | 37 ++++++- src/parser/program.rs | 17 ++- src/token.rs | 26 ++--- 14 files changed, 771 insertions(+), 59 deletions(-) create mode 100644 src/ir/expr.rs create mode 100644 src/ir/mod.rs create mode 100644 src/ir/pattern.rs create mode 100644 src/ir/types.rs create mode 100644 src/ir/value.rs diff --git a/sample-initial.amo b/sample-initial.amo index 95d3d7b..2f4e8d4 100644 --- a/sample-initial.amo +++ b/sample-initial.amo @@ -1,18 +1,6 @@ -MyType: Type -MyType = type - Variant1 - | Variant2 (int 0..usize) - | Variant3 str (int 0..21) +main: Int +main = 1 + (if (distance_squared 10 2) > 10 then 1000 else 2000) -myFunc: str, int -> MyType -myFunc strval intval = - if intval < 21 && intval > 0 - then Variant3 strval intval - else Variant1 -ComplexType: Type -ComplexType = type - ComplexVariant (str, int -> MyType) str - -myVal : ComplexType -myVal = ComplexVariant myFunc "uwu~" +distance_squared: Int, Int -> Int +distance_squared a b = a * a + b * b diff --git a/src/ir/expr.rs b/src/ir/expr.rs new file mode 100644 index 0000000..e62fdc6 --- /dev/null +++ b/src/ir/expr.rs @@ -0,0 +1,92 @@ +use core::fmt; +use std::{collections::LinkedList, mem}; + +use super::{value::Value, pattern::Pattern, Identifier}; + +#[derive(Debug)] +pub struct Expr { + pub identifier: Identifier, + pub operation: Operation, + pub formals: Vec, +} + +impl fmt::Display for Expr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Operation::NoOp = self.operation { + self.identifier.fmt(f) + } else { + write!(f, + "{} = {:?}{}", + self.identifier, + self.operation, + self.formals.iter() + .map(|f| format!(" {f}")) + .collect::(), + ) + } + } +} + +pub enum Operation { + Add, + Sub, + Mul, + Div, + Mod, + Range, + Eq, + NEq, + LessThan, + GreaterThan, + LAnd, + LOr, + Const(Value), + Call, + VariantUnion, + FunctionType, + NoOp, + Conditional(Vec<(Pattern, LinkedList)>), +} + +impl fmt::Debug for Operation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Add => "plus", + Self::Sub => "minus", + Self::Mul => "times", + Self::Div => "div", + Self::Mod => "mod", + Self::Range => "to", + Self::Eq => "equals", + Self::NEq => "nequals", + Self::LessThan => "lessthan", + Self::GreaterThan => "morethan", + Self::LAnd => "and", + Self::LOr => "or", + Self::Const(v) => { + return write!(f, "const[{v:?}]"); + }, + Self::Call => "call", + Self::VariantUnion => "orvariant", + Self::FunctionType => "yields", + Self::NoOp => "noop", + Self::Conditional(branches) => { + return write!(f, "cond({branches:?})"); + }, + }) + } +} + +pub fn set_last_ident_name(mut exprs: LinkedList, name: String) -> LinkedList { + if let Some(expr) = exprs.back_mut() { + let mut placeholder = Identifier::ROOT; + mem::swap(&mut expr.identifier, &mut placeholder); + placeholder = placeholder.set_name(name); + mem::swap(&mut expr.identifier, &mut placeholder); + } + exprs +} + +pub fn get_last_ident(exprs: &LinkedList) -> Option { + exprs.back().map(|expr| expr.identifier.clone()) +} diff --git a/src/ir/mod.rs b/src/ir/mod.rs new file mode 100644 index 0000000..4c213a7 --- /dev/null +++ b/src/ir/mod.rs @@ -0,0 +1,118 @@ +use core::fmt; + +use crate::cons; + +use self::{types::Type, value::Value}; + +pub mod types; +pub mod expr; +pub mod value; +pub mod pattern; + +#[derive(Debug, Clone, Eq, PartialEq)] +// name id depth +pub struct Identifier(pub String, usize, usize); + +impl Identifier { + pub const ROOT: Identifier = Identifier(String::new(), 1, 0); + + pub fn subid_with_name(&self, new_name: String, index: u32) -> Identifier { + Identifier ( + new_name, + self.1 * nth_prime(self.2).pow(index + 1), + self.2 + 1 + ) + } + + pub fn subid_generate_name(&self, short_name: &str, index: u32) -> Identifier { + self.subid_with_name(format!("{}.{short_name}", self.0), index) + } + + pub fn matches(&self, name: &str) -> bool { + name == self.0.as_str() + } + + pub fn set_name(self, new_name: String) -> Identifier { + Identifier(new_name, self.1, self.2) + } +} + +impl fmt::Display for Identifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}.{}", self.0, self.1) + } +} + +#[derive(Debug)] +pub enum IrError { + MismatchedNames(String, String), + Undefined(String), + MissingExpression, + NestedTypeDeclarations, +} + +pub type Result = std::result::Result; + +// note: the 0th prime is 2 +pub fn nth_prime(n: usize) -> usize { + nth_prime_from(n, 3, vec![2]) +} + +pub fn nth_prime_from(n: usize, i: usize, known_primes: Vec) -> usize { + if is_prime(i, &known_primes) { + if known_primes.len() > n { + *known_primes.last().unwrap() + } else { + nth_prime_from(n, i + 2, cons(known_primes, i)) + } + } else { + nth_prime_from(n, i + 2, known_primes) + } +} + +pub fn is_prime(x: usize, known_primes: &[usize]) -> bool { + !known_primes.iter() + .take_while(|p| **p * **p < x) + .any(|p| x % *p == 0) +} + +#[derive(Debug)] +pub struct Declaration { + pub identifier: Identifier, + pub value_type: Type, + pub value: Value, +} + +impl fmt::Display for Declaration { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, + "{0} is of type {1} and has value\n{2}", + self.identifier, + self.value_type, + self.value, + ) + } +} + +#[derive(Debug, Clone)] +pub struct BindingScope<'a>(Option<&'a BindingScope<'a>>, Vec); + +impl<'a> BindingScope<'a> { + pub const ROOT: BindingScope<'static> = BindingScope(None, Vec::new()); + + pub fn bind(&self, idents: Vec) -> BindingScope { + BindingScope(Some(self), idents) + } + + pub fn bind_single(self, ident: Identifier) -> BindingScope<'a> { + BindingScope(self.0, cons(self.1, ident)) + } + + pub fn lookup(&self, name: &str) -> Option<&Identifier> { + let BindingScope(next_scope, identifiers) = self; + identifiers.iter() + .find(|ident| ident.matches(name)) + .or_else(|| next_scope.and_then(|s| s.lookup(name))) + } +} + diff --git a/src/ir/pattern.rs b/src/ir/pattern.rs new file mode 100644 index 0000000..f1135bd --- /dev/null +++ b/src/ir/pattern.rs @@ -0,0 +1,10 @@ +use crate::token::Literal; + +use super::Identifier; + +#[derive(Debug)] +pub enum Pattern { + Literal(Literal), + Binding(Identifier), + Variant(Identifier, Vec), +} diff --git a/src/ir/types.rs b/src/ir/types.rs new file mode 100644 index 0000000..94f3db3 --- /dev/null +++ b/src/ir/types.rs @@ -0,0 +1,73 @@ +use core::fmt; + +use super::Identifier; + +#[derive(Debug)] +pub struct Variant { + pub name: Identifier, + pub elements: Vec, +} + +impl fmt::Display for Variant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, + "{} {}", + self.name, + self.elements.iter() + .map(|e| e.to_string()) + .collect::>() + .join(" "), + ) + } +} + +#[derive(Debug)] +pub enum Type { + UserDefined(Vec), + Function(Vec, Box), + Primitive(PrimitiveType), +} + +impl fmt::Display for Type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::UserDefined(variants) => + f.write_str( + variants.into_iter() + .map(ToString::to_string) + .collect::>() + .join(" | ") + .as_str() + ), + Self::Function(args, return_type) => + write!(f, + "{} -> {}", + args.into_iter() + .map(ToString::to_string) + .collect::>() + .join(" , "), + return_type + ), + Self::Primitive(p) => p.fmt(f), + } + } +} + +#[derive(Debug)] +pub enum PrimitiveType { + Int, + Str, + Type, +} + +impl fmt::Display for PrimitiveType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str( + match self { + Self::Int => "int", + Self::Str => "str", + Self::Type => "Type", + } + ) + } +} diff --git a/src/ir/value.rs b/src/ir/value.rs new file mode 100644 index 0000000..c0375a0 --- /dev/null +++ b/src/ir/value.rs @@ -0,0 +1,32 @@ +use core::fmt; +use std::collections::LinkedList; + +use super::{expr::Expr, Identifier}; + +#[derive(Debug)] +pub enum Value { + Int(usize), + String(String), + Function(Vec, LinkedList), + Structural(usize, Vec), +} + +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Int(v) => write!(f, "{}", v), + Self::String(val) => write!(f, "\"{val}\""), + Self::Function(args, exprs) => write!(f, + "function({}):{}", + args.into_iter() + .map(|a| a.to_string()) + .collect::>() + .join(", "), + exprs.into_iter() + .map(|e| format!("\n\t{e}")) + .collect::(), + ), + Self::Structural(_, _) => todo!(), + } + } +} diff --git a/src/main.rs b/src/main.rs index 3826c91..ff9057b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,9 +28,22 @@ fn main() -> std::io::Result<()> { }; println!("Parse successful!!"); - for decl in program.0 { + for decl in &program.0 { println!("{decl:?}\n"); } + + println!("Building IR..."); + match program.gen_ir() { + Ok(program) => + println!( + "IR built successfully!\n{}", + program.into_iter() + .map(|decl| format!("\n\n{decl}")) + .collect::(), + ), + Err(e) => + println!("Oh noes! {e:?}"), + } Ok(()) } @@ -48,3 +61,8 @@ pub fn join(mut a: LinkedList, mut b: LinkedList) -> LinkedList { a.append(&mut b); a } + +pub fn join_vec(mut a: Vec, mut b: Vec) -> Vec { + a.append(&mut b); + a +} diff --git a/src/parser/declaration.rs b/src/parser/declaration.rs index 185dbee..10fe3f1 100644 --- a/src/parser/declaration.rs +++ b/src/parser/declaration.rs @@ -1,6 +1,6 @@ use std::mem::{Discriminant, discriminant}; -use crate::token::Token; +use crate::{token::Token, ir::{self, IrError, Identifier, BindingScope, types::{Type, PrimitiveType}}}; use super::{Parsable, WrappedLexer, ParseError, absorb_token_or_error, expr::Expr}; @@ -48,3 +48,32 @@ impl Parsable for Declaration { } } } + +impl Declaration { + pub fn gen_ir(self, bindings: &BindingScope, index: u32, parent_id: Identifier) -> Result, IrError> { + let Declaration { name, type_, name2, args, value } = self; + if name != name2 { + Err(IrError::MismatchedNames(name, name2)) + } else { + let own_id = parent_id.subid_with_name(name, index); + let args = args.into_iter() + .enumerate() + .map(|(i, variable_name)| own_id.subid_with_name(variable_name, i as u32)) + .collect::>(); + 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)?; + Ok(Some( + ir::Declaration { + identifier: own_id, + value_type: Type::Primitive(PrimitiveType::Int), // TODO + value: ir::value::Value::Function(args, expression_dag), + } + )) + } + } + + pub fn get_identifier(&self, parent: &Identifier, index: u32) -> Option { + Some(parent.subid_with_name(self.name.clone(), index)) + } +} diff --git a/src/parser/expr.rs b/src/parser/expr.rs index e0fc275..f01ecf8 100644 --- a/src/parser/expr.rs +++ b/src/parser/expr.rs @@ -13,11 +13,11 @@ // // ::= Aro -use std::mem::{Discriminant, discriminant}; +use std::{mem::{Discriminant, discriminant}, collections::LinkedList}; -use crate::token::{Literal, Token}; +use crate::{token::{Literal, Token}, ir::{self, Identifier, expr::{Operation, set_last_ident_name}, BindingScope, pattern::Pattern, IrError}, cons_ll, join}; -use super::{Parsable, pattern::BindingPattern, infix::Rank1Exp, ParseError, WrappedLexer, absorb_token_or_error, parse_delineated_vec}; +use super::{Parsable, pattern::BindingPattern, infix::{Rank1Exp, GenIR}, ParseError, WrappedLexer, absorb_token_or_error, parse_delineated_vec}; #[derive(Debug)] pub enum Expr { @@ -73,6 +73,90 @@ impl Parsable for Expr { } } +impl Expr { + pub fn gen_ir( + self, + bindings: &BindingScope, + parent: &Identifier, + index: u32, + type_context: bool + ) -> ir::Result> { + match self { + Self::If(cond, if_block) => { + let self_ident = parent.subid_generate_name("ifblk", index); + let preceding_expressions = cond.gen_ir(bindings, &self_ident, 0, type_context)?; + let conditional = Operation::Conditional(match *if_block { + IfBlock::IfIs(case, more_cases) => { + Some(case).into_iter() + .chain(more_cases) + .enumerate() + .map(|(i, Case(pattern, expr))| { + let (pattern_bindings, pattern) = pattern.gen_ir(bindings, &self_ident, 2 * i as u32)?; + let new_scope = bindings.bind(pattern_bindings); + let new_exprs = expr.gen_ir(&new_scope, &self_ident, 2*i as u32 + 1, type_context)?; + Ok((pattern, new_exprs)) + }) + .collect::>>() + } + IfBlock::IfThen(positive, negative) => { + vec![negative, positive] + .into_iter() + .enumerate() + .map(|(v, expr)| + expr.gen_ir(bindings, &self_ident, v as u32, type_context).map(|expr| + (Pattern::Literal(Literal::Int(v as u64)), expr) + ) + ) + .collect() + } + }?); + let new_expr = ir::expr::Expr { + identifier: self_ident, + operation: conditional, + formals: vec![preceding_expressions.back() + .ok_or(IrError::MissingExpression)? + .identifier + .clone()] + }; + Ok(cons_ll(preceding_expressions, new_expr)) + } + Self::Let(first_let, more_lets, finally) => { + let self_ident = parent.subid_generate_name("letmany", index); + let n_lets = more_lets.len() + 1; + let (bindings, prior_exprs) = [*first_let].into_iter() + .chain(more_lets) + .enumerate() + .try_fold( + (bindings.bind(Vec::with_capacity(n_lets)), LinkedList::new()), + |(bindings, exprs), (i, LetStmt(name, parsetree))| { + let new_exprs = set_last_ident_name( + parsetree.gen_ir(&bindings, &self_ident, i as u32, type_context)?, + name + ); + let new_bindings = bindings.bind_single( + new_exprs.back() + .ok_or(IrError::MissingExpression)? + .identifier + .clone() + ); + Ok((new_bindings, join(exprs, new_exprs))) + } + )?; + let exprs = finally.gen_ir(&bindings, &self_ident, n_lets as u32, type_context)?; + Ok(join(prior_exprs, exprs)) + } + Self::Infix(infix) => infix.gen_ir(bindings, parent, index, type_context), + Self::Type(expr) => + if type_context { + Err(IrError::NestedTypeDeclarations) + } else { + expr.gen_ir(bindings, parent, index, true) + } + } + } +} + +// todo: refactor this to infix #[derive(Debug)] pub enum TightExpr { Literal(Literal), diff --git a/src/parser/infix.rs b/src/parser/infix.rs index f2bddf4..ea1447f 100644 --- a/src/parser/infix.rs +++ b/src/parser/infix.rs @@ -1,11 +1,228 @@ -use crate::token::{InfixRank1, InfixRank2, InfixRank3, InfixRank5, InfixRank6, InfixRank7}; +use std::collections::LinkedList; + +use crate::{token::{InfixRank1, InfixRank2, InfixRank3, InfixRank5, InfixRank6, Literal, InfixRank4}, ir::{BindingScope, Identifier, self, expr::{get_last_ident, Operation, Expr}, IrError, value::Value}, join, cons_ll, cons}; use super::expr::TightExpr; pub type Rank1Exp = (Rank2Exp, Vec<(InfixRank1, Rank2Exp)>); pub type Rank2Exp = (Rank3Exp, Vec<(InfixRank2, Rank3Exp)>); pub type Rank3Exp = (Rank4Exp, Vec<(InfixRank3, Rank4Exp)>); -pub type Rank4Exp = (Rank5Exp, Vec< Rank5Exp>); +pub type Rank4Exp = (Rank5Exp, Vec<(InfixRank4, Rank5Exp)>); pub type Rank5Exp = (Rank6Exp, Vec<(InfixRank5, Rank6Exp)>); pub type Rank6Exp = (Rank7Exp, Vec<(InfixRank6, Rank7Exp)>); -pub type Rank7Exp = (Box, Vec<(InfixRank7, TightExpr)>); +pub type Rank7Exp = (Box, Vec< TightExpr>); + +pub trait GenIR { + fn gen_ir( + self, + bindings: &BindingScope, + parent: &Identifier, + index: u32, + type_context: bool, + ) -> ir::Result>; +} + +pub trait InfixOp { + fn gen_ir(&self) -> Operation; +} + +impl InfixOp for InfixRank1 { + fn gen_ir(&self) -> Operation { + match self { + Self::LOr => Operation::LOr, + Self::VBar => Operation::VariantUnion, + } + } +} + +impl InfixOp for InfixRank2 { + fn gen_ir(&self) -> Operation { + match self { + Self::LAnd => Operation::LAnd, + Self::Aro => Operation::FunctionType, + } + } +} + +impl InfixOp for InfixRank3 { + fn gen_ir(&self) -> Operation { + match self { + Self::Eq => Operation::Eq, + Self::NEq => Operation::NEq, + Self::LessThan => Operation::LessThan, + Self::GreaterThan => Operation::GreaterThan, + } + } +} + +impl InfixOp for InfixRank4 { + fn gen_ir(&self) -> Operation { + Operation::Range + } +} + +impl InfixOp for InfixRank5 { + fn gen_ir(&self) -> Operation { + match self { + Self::Add => Operation::Add, + Self::Sub => Operation::Sub, + } + } +} + +impl InfixOp for InfixRank6 { + fn gen_ir(&self) -> Operation { + match self { + Self::Mul => Operation::Mul, + Self::Mod => Operation::Mod, + Self::Div => Operation::Div, + } + } +} + +impl GenIR for (NextRank, Vec<(Op, NextRank2)>) { + fn gen_ir( + self, + bindings: &BindingScope, + parent: &Identifier, + index: u32, + type_context: bool, + ) -> ir::Result> { + let (first_arg, ops) = self; + if !ops.is_empty() { + let ident = parent.subid_with_name(String::new(), index); + let prior_expressions = first_arg.gen_ir(bindings, &ident, 0, type_context)?; + (prior_expressions, ops).gen_ir(bindings, &ident, 1, type_context) + } else { + first_arg.gen_ir(bindings, parent, index, type_context) + } + } +} + +impl GenIR for (LinkedList, Vec<(Op, NextRank)>) { + fn gen_ir( + self, + bindings: &BindingScope, + parent: &Identifier, + index: u32, + type_context: bool, + ) -> ir::Result> { + 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 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)?; + let first_arg_name = &first_arg_ident.0; + let second_arg_name = &second_arg_ident.0; + let final_name = format!("{first_arg_name}-{op:?}-{second_arg_name}"); + let this_ident = this_ident.set_name(final_name); + let new_expr = ir::expr::Expr { + identifier: this_ident, + operation: op, + formals: vec![first_arg_ident, second_arg_ident], + }; + 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) + } else { + Ok(first_arg_exprs) + } + } +} + +//pub type Rank4Exp = (TightExpr, Vec); +impl GenIR for Rank7Exp { + fn gen_ir( + self, + bindings: &BindingScope, + parent: &Identifier, + index: u32, + type_context: bool, + ) -> ir::Result> { + let (thing_to_be_called, arguments) = self; + if arguments.is_empty() { + thing_to_be_called.gen_ir(bindings, parent, index, type_context) + } else { + let this_ident = parent.subid_with_name(String::new() /*will replace*/, index); + let n_args = arguments.len() + 1; + let (arg_idents, prior_exprs) = Some(*thing_to_be_called) + .into_iter() + .chain(arguments) + .enumerate() + .map(|(i, arg)| arg.gen_ir(bindings, &this_ident, i as u32, type_context)) + .try_fold( + (Vec::with_capacity(n_args), LinkedList::new()), + |(idents, exprs), new_exprs| + new_exprs.and_then(|new_exprs2| + Ok(( + cons( + idents, + get_last_ident(&new_exprs2).ok_or(IrError::MissingExpression)? + ), + join(exprs, new_exprs2) + )) + ) + )?; + let call_ident_name = &arg_idents.get(0).ok_or(IrError::MissingExpression)?.0; + let new_ident_name = format!("{call_ident_name}_result"); + let new_expr = ir::expr::Expr { + identifier: this_ident.set_name(new_ident_name), + operation: Operation::Call, + formals: arg_idents, + }; + Ok(cons_ll(prior_exprs, new_expr)) + } + } +} + +impl GenIR for TightExpr { + fn gen_ir( + self, + bindings: &BindingScope, + parent: &Identifier, + index: u32, + type_context: bool, + ) -> ir::Result> { + match self { + TightExpr::Literal(l) => { + let value = match l { + Literal::String(s) => Value::String(s), + Literal::Int(i) => Value::Int(i as usize), + }; + let expr = ir::expr::Expr { + identifier: parent.subid_with_name(format!("literal"), index), + operation: Operation::Const(value), + formals: Vec::new(), + }; + Ok(LinkedList::from([expr])) + }, + TightExpr::Grouped(e) => e.gen_ir(bindings, parent, index, type_context), + TightExpr::Symbol(s) => + if let Some(ident) = bindings.lookup(&s) { + Ok(LinkedList::from([Expr { + identifier: ident.clone(), + operation: Operation::NoOp, + formals: Vec::new(), + }])) + } else if type_context { + todo!("Custom types aren't implemented yet") + } else { + Err(IrError::Undefined(s)) + }, + } + } +} + +impl GenIR for Box { + fn gen_ir( + self, + bindings: &BindingScope, + parent: &Identifier, + index: u32, + type_context: bool, + ) -> ir::Result> { + (*self).gen_ir(bindings, parent, index, type_context) + } +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 2de893e..35133ff 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -14,7 +14,7 @@ use std::{ops::Range, mem::{Discriminant, self}}; use logos::Lexer; -use crate::{token::{Token, InfixRank1, InfixRank7, InfixRank6, InfixRank5, InfixRank3, InfixRank2}, cons}; +use crate::{token::{Token, InfixRank1, InfixRank6, InfixRank5, InfixRank3, InfixRank2, InfixRank4}, cons}; use std::mem::discriminant; pub mod program; @@ -28,6 +28,7 @@ pub trait Parsable: Sized { fn parse(l: &mut WrappedLexer) -> Result; fn matches(l: &Token) -> bool { let (expected, can_zero_width) = Self::expected(); + eprintln!("{expected:?} {l:?}"); can_zero_width || expected.contains(&discriminant(l)) } } @@ -218,9 +219,26 @@ impl Parsable for InfixRank3 { } } +impl Parsable for InfixRank4 { + fn expected() -> (Vec>, bool) { + (vec![discriminant(&Token::R4Infix(InfixRank4::Range))], false) + } + + fn parse(l: &mut WrappedLexer) -> Result { + let span = l.span(); + match l.monch() { + Token::R4Infix(o) => Ok(o), + _ => Err(ParseError { + location: span, + expected: Self::expected().0 + }), + } + } +} + impl Parsable for InfixRank5 { fn expected() -> (Vec>, bool) { - (vec![discriminant(&Token::R5Infix(InfixRank5::Range))], false) + (vec![discriminant(&Token::R5Infix(InfixRank5::Add))], false) } fn parse(l: &mut WrappedLexer) -> Result { @@ -237,7 +255,7 @@ impl Parsable for InfixRank5 { impl Parsable for InfixRank6 { fn expected() -> (Vec>, bool) { - (vec![discriminant(&Token::R6Infix(InfixRank6::Add))], false) + (vec![discriminant(&Token::R6Infix(InfixRank6::Mul))], false) } fn parse(l: &mut WrappedLexer) -> Result { @@ -251,20 +269,3 @@ impl Parsable for InfixRank6 { } } } - -impl Parsable for InfixRank7 { - fn expected() -> (Vec>, bool) { - (vec![discriminant(&Token::R7Infix(InfixRank7::Mul))], false) - } - - fn parse(l: &mut WrappedLexer) -> Result { - let span = l.span(); - match l.monch() { - Token::R7Infix(o) => Ok(o), - _ => Err(ParseError { - location: span, - expected: Self::expected().0 - }), - } - } -} diff --git a/src/parser/pattern.rs b/src/parser/pattern.rs index a27ddd4..e3e4f03 100644 --- a/src/parser/pattern.rs +++ b/src/parser/pattern.rs @@ -5,7 +5,7 @@ use std::mem::{discriminant, Discriminant}; -use crate::token::{Literal, Token}; +use crate::{token::{Literal, Token}, ir::{BindingScope, Identifier, pattern::Pattern, self, IrError}, cons, join_vec}; use super::{Parsable, ParseError, WrappedLexer, absorb_token_or_error}; @@ -16,6 +16,22 @@ pub enum TightBindingPattern { Group(BindingPattern), } +impl TightBindingPattern { + pub fn gen_ir(self, scope: &BindingScope, parent_ident: &Identifier, index: u32) -> ir::Result<(Vec, Pattern)> { + match self { + TightBindingPattern::Literal(l) => Ok((Vec::new(), Pattern::Literal(l))), + TightBindingPattern::Symbol(s) => { + let ident = parent_ident.subid_with_name(s, index); + Ok(( + vec![ident.clone()], + Pattern::Binding(ident), + )) + } + TightBindingPattern::Group(bp) => bp.gen_ir(scope, parent_ident, index), + } + } +} + impl Parsable for TightBindingPattern { fn expected() -> (Vec>, bool) { ( @@ -64,3 +80,22 @@ impl Parsable for BindingPattern { Ok(Self(name, fields)) } } + +impl BindingPattern { + pub fn gen_ir(self, scope: &BindingScope, parent_ident: &Identifier, index: u32) -> ir::Result<(Vec, Pattern)> { + let BindingPattern(variant, elements) = self; + let self_ident = parent_ident.subid_generate_name(&variant, index); + let variant_ident = scope.lookup(&variant).ok_or(IrError::Undefined(variant))?; + let (idents, patts) = elements.into_iter() + .enumerate() + .map(|(idx, patt)| patt.gen_ir(scope, &self_ident, idx as u32)) + .try_fold( + (Vec::new(), Vec::with_capacity(8)), + |(found_identifiers, found_patterns), res| { + let (new_idents, new_patt) = res?; + Ok((join_vec(found_identifiers, new_idents), cons(found_patterns, new_patt))) + } + )?; + Ok((idents, Pattern::Variant(variant_ident.clone(), patts))) + } +} diff --git a/src/parser/program.rs b/src/parser/program.rs index 340501d..63fdc8e 100644 --- a/src/parser/program.rs +++ b/src/parser/program.rs @@ -1,6 +1,6 @@ use std::mem::{discriminant, Discriminant}; -use crate::{token::Token, cons}; +use crate::{token::Token, cons, ir::{self, BindingScope, Identifier}}; use super::{ParseError, Parsable, WrappedLexer, declaration::Declaration}; @@ -32,3 +32,18 @@ fn parse_program_inner(l: &mut WrappedLexer, acc: Vec) -> Result ir::Result> { + // We need a first pass to generate a list of all of the identifiers + 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:?}"); + self.0.into_iter() + .enumerate() + .filter_map(|(i, decl)| decl.gen_ir(&root_scope, i as u32, Identifier::ROOT).transpose()) + .collect() + } +} diff --git a/src/token.rs b/src/token.rs index 5df396d..07c9590 100644 --- a/src/token.rs +++ b/src/token.rs @@ -158,23 +158,23 @@ pub enum Token { /// A rank 5 infix binop (binary operator) /// /// i.e. Range - #[token("..", |_| InfixRank5::Range)] - R5Infix(InfixRank5), //d21 + #[token("..", |_| InfixRank4::Range)] + R4Infix(InfixRank4), //d21 /// A rank 6 infix binop (binary operator) /// /// i.e. Addition & Subtraction - #[token("+", |_| InfixRank6::Add)] - #[token("-", |_| InfixRank6::Sub)] - R6Infix(InfixRank6), //d22 + #[token("+", |_| InfixRank5::Add)] + #[token("-", |_| InfixRank5::Sub)] + R5Infix(InfixRank5), //d22 /// A rank 7 (applied first) infix binop (binary operator) /// /// i.e. Multiplication, Division, and Modulo - #[token("*", |_| InfixRank7::Mul)] - #[token("/", |_| InfixRank7::Div)] - #[token("%", |_| InfixRank7::Mod)] - R7Infix(InfixRank7), //d23 + #[token("*", |_| InfixRank6::Mul)] + #[token("/", |_| InfixRank6::Div)] + #[token("%", |_| InfixRank6::Mod)] + R6Infix(InfixRank6), //d23 /// Some literal (a constant value represented textually) /// @@ -185,7 +185,7 @@ pub enum Token { Literal(Literal), //d24 /// Some symbol, usually a variable or a type - #[regex(r"[a-zA-Z][a-zA-Z\d]*", |lex| lex.slice().to_string(), priority = 0)] + #[regex(r"[a-zA-Z_][a-zA-Z\d_]*", |lex| lex.slice().to_string(), priority = 0)] Symbol(String), //d25 /// An opening `[` square bracket @@ -305,7 +305,7 @@ pub enum InfixRank3 { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum InfixRank5 { +pub enum InfixRank4 { /// The additive operator. /// /// Takes two numeric values and returns a range from the first to the second @@ -313,7 +313,7 @@ pub enum InfixRank5 { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum InfixRank6 { +pub enum InfixRank5 { /// The additive operator. /// /// Takes two numeric values and returns their sum @@ -326,7 +326,7 @@ pub enum InfixRank6 { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum InfixRank7 { +pub enum InfixRank6 { /// The multiplicitive operator. /// /// Takes two numeric values and returns their product