conlang 0.3.0: Total grammar overhaul

- Rewrote the grammar
- Rewrote the AST
- Rewrote the Parser
- Removed pretty printer (now handled by ast::ast_impl::Pretty, a Writer wrapper)
- Added items, and new keywords to go with them
  - Syntax is ~maybe temporary, based on Rust syntax
This commit is contained in:
John 2024-01-21 05:32:18 -06:00
parent 5e2f365f45
commit c4a32895df
12 changed files with 3541 additions and 2905 deletions

View File

@ -4,7 +4,7 @@ resolver = "2"
[workspace.package] [workspace.package]
repository = "https://git.soft.fish/j/Conlang" repository = "https://git.soft.fish/j/Conlang"
version = "0.0.2" version = "0.0.3"
authors = ["John Breaux <j@soft.fish>"] authors = ["John Breaux <j@soft.fish>"]
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"

View File

@ -1,4 +1,8 @@
//! Utilities for cl-frontend //! Utilities for cl-frontend
//!
//! # TODO
//! - [ ] Readline-like line editing
//! - [ ] Raw mode?
pub mod args { pub mod args {
use crate::cli::Mode; use crate::cli::Mode;
@ -14,7 +18,7 @@ pub mod args {
pub repl: bool, // defaults true if stdin is terminal pub repl: bool, // defaults true if stdin is terminal
pub mode: Mode, // defaults Interpret pub mode: Mode, // defaults Interpret
} }
const HELP: &str = "[( --repl | --no-repl )] [( -f | --file ) <filename>]"; const HELP: &str = "[( --repl | --no-repl )] [--mode (tokens | pretty | type | run)] [( -f | --file ) <filename>]";
impl Args { impl Args {
pub fn new() -> Self { pub fn new() -> Self {
@ -65,109 +69,132 @@ pub mod args {
} }
pub mod program { pub mod program {
use std::io::{Result as IOResult, Write}; use std::{fmt::Display, io::Write};
use conlang::{ use conlang::{
ast::preamble::{expression::Expr, *}, ast::{self, ast_impl::format::Pretty},
interpreter::{env::Environment, error::IResult}, interpreter::{
env::Environment, error::IResult, interpret::Interpret, temp_type_impl::ConValue,
},
// pretty_printer::{PrettyPrintable, Printer},
lexer::Lexer, lexer::Lexer,
parser::{error::PResult, Parser}, parser::{error::PResult, Parser},
pretty_printer::{PrettyPrintable, Printer}, resolver::{error::TyResult, Resolver},
resolver::{error::TyResult, Resolve, Resolver},
token::Token,
}; };
pub struct Tokenized { pub struct Parsable;
tokens: Vec<Token>,
}
pub enum Parsed { pub enum Parsed {
Program(Start), File(ast::File),
Expr(Expr), Stmt(ast::Stmt),
Expr(ast::Expr),
} }
impl TryFrom<Tokenized> for Parsed { pub struct Program<'t, Variant> {
type Error = conlang::parser::error::Error; text: &'t str,
fn try_from(value: Tokenized) -> Result<Self, Self::Error> {
let mut parser = Parser::new(value.tokens);
let ast = parser.parse()?;
//if let Ok(ast) = ast {
//return
Ok(Self::Program(ast))
//}
//Ok(Self::Expr(parser.reset().parse_expr()?))
}
}
pub struct Program<Variant> {
data: Variant, data: Variant,
} }
impl<'t, V> Program<'t, V> {
impl Program<Tokenized> { pub fn lex(&self) -> Lexer {
pub fn new(input: &str) -> Result<Self, Vec<conlang::lexer::error::Error>> { Lexer::new(self.text)
let mut tokens = vec![];
let mut errors = vec![];
for token in Lexer::new(input) {
match token {
Ok(token) => tokens.push(token),
Err(error) => errors.push(error),
}
}
if errors.is_empty() {
Ok(Self { data: Tokenized { tokens } })
} else {
Err(errors)
}
}
pub fn tokens(&self) -> &[Token] {
&self.data.tokens
}
pub fn parse(self) -> PResult<Program<Parsed>> {
Ok(Program { data: Parsed::try_from(self.data)? })
} }
} }
impl Program<Parsed> { impl<'t> Program<'t, Parsable> {
pub fn new(text: &'t str) -> Self {
Self { text, data: Parsable }
}
pub fn parse(self) -> PResult<Program<'t, Parsed>> {
self.parse_file().or_else(|_| self.parse_stmt())
}
pub fn parse_expr(&self) -> PResult<Program<'t, Parsed>> {
Ok(Program { data: Parsed::Expr(Parser::new(self.lex()).expr()?), text: self.text })
}
pub fn parse_stmt(&self) -> PResult<Program<'t, Parsed>> {
Ok(Program { data: Parsed::Stmt(Parser::new(self.lex()).stmt()?), text: self.text })
}
pub fn parse_file(&self) -> PResult<Program<'t, Parsed>> {
Ok(Program { data: Parsed::File(Parser::new(self.lex()).file()?), text: self.text })
}
}
impl<'t> Program<'t, Parsed> {
pub fn debug(&self) {
match &self.data {
Parsed::File(v) => eprintln!("{v:?}"),
Parsed::Stmt(v) => eprintln!("{v:?}"),
Parsed::Expr(v) => eprintln!("{v:?}"),
}
}
pub fn print(&self) {
let mut f = std::io::stdout().pretty();
let _ = match &self.data {
Parsed::File(v) => writeln!(f, "{v}"),
Parsed::Stmt(v) => writeln!(f, "{v}"),
Parsed::Expr(v) => writeln!(f, "{v}"),
};
// println!("{self}")
}
pub fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<()> { pub fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<()> {
match &mut self.data { todo!("Program::resolve(\n{self},\n{resolver:?}\n)")
Parsed::Program(start) => start.resolve(resolver),
Parsed::Expr(expr) => expr.resolve(resolver),
} }
.map(|ty| println!("{ty}"))
} pub fn run(&self, env: &mut Environment) -> IResult<ConValue> {
/// Runs the [Program] in the specified [Environment]
pub fn run(&self, env: &mut Environment) -> IResult<()> {
println!(
"{}",
match &self.data { match &self.data {
Parsed::Program(start) => env.eval(start)?, Parsed::File(v) => v.interpret(env),
Parsed::Expr(expr) => env.eval(expr)?, Parsed::Stmt(v) => v.interpret(env),
} Parsed::Expr(v) => v.interpret(env),
);
Ok(())
} }
} }
impl PrettyPrintable for Program<Parsed> { // pub fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<()> {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> { // match &mut self.data {
// Parsed::Program(start) => start.resolve(resolver),
// Parsed::Expr(expr) => expr.resolve(resolver),
// }
// .map(|ty| println!("{ty}"))
// }
// /// Runs the [Program] in the specified [Environment]
// pub fn run(&self, env: &mut Environment) -> IResult<()> {
// println!(
// "{}",
// match &self.data {
// Parsed::Program(start) => env.eval(start)?,
// Parsed::Expr(expr) => env.eval(expr)?,
// }
// );
// Ok(())
// }
}
impl<'t> Display for Program<'t, Parsed> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.data { match &self.data {
Parsed::Program(value) => value.visit(p), Parsed::File(v) => write!(f, "{v}"),
Parsed::Expr(value) => value.visit(p), Parsed::Stmt(v) => write!(f, "{v}"),
Parsed::Expr(v) => write!(f, "{v}"),
} }
} }
} }
// impl PrettyPrintable for Program<Parsed> {
// fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
// match &self.data {
// Parsed::Program(value) => value.visit(p),
// Parsed::Expr(value) => value.visit(p),
// }
// }
// }
} }
pub mod cli { pub mod cli {
use conlang::{ use conlang::{interpreter::env::Environment, resolver::Resolver, token::Token};
interpreter::env::Environment, pretty_printer::PrettyPrintable, resolver::Resolver,
token::Token,
};
use crate::{ use crate::{
args::Args, args::Args,
program::{Parsed, Program, Tokenized}, program::{Parsable, Parsed, Program},
}; };
use std::{ use std::{
convert::Infallible, convert::Infallible,
@ -220,35 +247,30 @@ pub mod cli {
} }
fn no_repl(mode: Mode, path: Option<&Path>, code: &str) { fn no_repl(mode: Mode, path: Option<&Path>, code: &str) {
let program = Program::new(code); let program = Program::new(code);
match (mode, program) { match mode {
(Mode::Tokenize, Ok(program)) => { Mode::Tokenize => {
for token in program.tokens() { for token in program.lex() {
if let Some(path) = path { if let Some(path) = path {
print!("{}:", path.display()); print!("{}:", path.display());
} }
print_token(token) match token {
} Ok(token) => print_token(&token),
} Err(e) => println!("{e}"),
(Mode::Beautify, Ok(program)) => Self::beautify(program),
(Mode::Resolve, Ok(program)) => Self::resolve(program, Default::default()),
(Mode::Interpret, Ok(program)) => Self::interpret(program, Environment::new()),
(_, Err(errors)) => {
for error in errors {
if let Some(path) = path {
eprint!("{}:", path.display());
}
eprintln!("{error}")
} }
} }
} }
Mode::Beautify => Self::beautify(program),
Mode::Resolve => Self::resolve(program, Default::default()),
Mode::Interpret => Self::interpret(program, Environment::new()),
} }
fn beautify(program: Program<Tokenized>) { }
fn beautify(program: Program<Parsable>) {
match program.parse() { match program.parse() {
Ok(program) => program.print(), Ok(program) => program.print(),
Err(e) => eprintln!("{e}"), Err(e) => eprintln!("{e}"),
}; };
} }
fn resolve(program: Program<Tokenized>, mut resolver: Resolver) { fn resolve(program: Program<Parsable>, mut resolver: Resolver) {
let mut program = match program.parse() { let mut program = match program.parse() {
Ok(program) => program, Ok(program) => program,
Err(e) => { Err(e) => {
@ -260,7 +282,7 @@ pub mod cli {
eprintln!("{e}"); eprintln!("{e}");
} }
} }
fn interpret(program: Program<Tokenized>, mut interpreter: Environment) { fn interpret(program: Program<Parsable>, mut interpreter: Environment) {
let program = match program.parse() { let program = match program.parse() {
Ok(program) => program, Ok(program) => program,
Err(e) => { Err(e) => {
@ -301,10 +323,10 @@ pub mod cli {
type Err = Infallible; type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Infallible> { fn from_str(s: &str) -> Result<Self, Infallible> {
Ok(match s { Ok(match s {
"i" | "interpret" => Mode::Interpret, "i" | "interpret" | "run" => Mode::Interpret,
"b" | "beautify" | "p" | "pretty" => Mode::Beautify, "b" | "beautify" | "p" | "pretty" => Mode::Beautify,
"r" | "resolve" | "typecheck" => Mode::Resolve, "r" | "resolve" | "typecheck" | "type" => Mode::Resolve,
"t" | "tokenize" => Mode::Tokenize, "t" | "tokenize" | "tokens" => Mode::Tokenize,
_ => Mode::Interpret, _ => Mode::Interpret,
}) })
} }
@ -386,12 +408,12 @@ pub mod cli {
continue; continue;
} }
// Lex the buffer, or reset and output the error // Lex the buffer, or reset and output the error
let code = match Program::new(&buf) { let code = Program::new(&buf);
Ok(code) => code, match code.lex().into_iter().find(|l| l.is_err()) {
Err(e) => { None => (),
for error in e { Some(Ok(_)) => unreachable!(),
Some(Err(error)) => {
eprintln!("{error}"); eprintln!("{error}");
}
self.reprompt(&mut buf); self.reprompt(&mut buf);
continue; continue;
} }
@ -451,9 +473,12 @@ pub mod cli {
Mode::Interpret => self.interpret(code), Mode::Interpret => self.interpret(code),
} }
} }
fn tokenize(&mut self, code: &Program<Tokenized>) { fn tokenize(&mut self, code: &Program<Parsable>) {
for token in code.tokens() { for token in code.lex() {
print_token(token); match token {
Ok(token) => print_token(&token),
Err(e) => println!("{e}"),
}
} }
} }
fn interpret(&mut self, code: &Program<Parsed>) { fn interpret(&mut self, code: &Program<Parsed>) {

View File

@ -1,84 +1,130 @@
(* Conlang Expression Grammar *) (* Conlang Expression Grammar *)
Start = Program ; Start = File ;
Program = Stmt* EOI ;
(* TODO: Mutability = "mut"? ;
- Replace Program with Module Visibility = "pub"? ;
Module = Decl* EOI ;
- Move Fn and Let into "Decl":
Decl = Fn | Let ; File = Item* EOI ;
- allow Decl | ExprStmt in Stmt:
Stmt = Decl | Expr ';' ;
*) Item = Visibility (
(* literal *) Const | Static | Module
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ; | Function | Struct | Enum
Bool = "true" | "false" ; | Impl
Identifier = IDENTIFIER ; ) ;
(* item *)
Const = "const" Identifier ':' Type = Expr ';' ;
Static = "static" Mutability Identifier ':' Type = Expr ';' ;
Module = "mod" Identifier '{' (Item)* '}' ;
Function = "fn" Identifier '(' (Param ',')* Param? ')' ( '->' Type) Block ;
Param = Identifier ':' Type ;
Struct = "struct" Identifier (TupleStruct | StructStruct)?;
StructStruct= '{' (Identifier ':' Type),* '}' ;
TupleStruct = TyTuple ;
Enum = "enum" Identifier (TupleEnum | StructEnum)? ;
TupleEnum = TyTuple;
StructEnum = '{' (Identifier ':' Type)* '}' ;
(* # Statements *)
(* statement *) (* statement *)
Stmt = Fn | Let | Expr ';' ; Stmt = ';' | (Let | Item | Expr ';'?) ;
Let = "let" Name ('=' Expr)? ';' ; Let = "let" Mutability Identifier (':' Ty)? ('=' Expr)? ;
Fn = "fn" Identifier '(' Params? ')' Block ; (* TODO: Closure syntax *)
(* TODO: Type system *) Closure = "cl" '(' Param* ')' Block ;
Params = (Name ',')* Name? ;
Name = "mut"? Identifier (':' Type )? ;
(* # Type Expressions *)
(* types *) (* type *)
TypeExpr = Never | Empty | TypeTuple | PathExpr ; Ty = Never | Empty | TyTuple | Path | TyRef | TyFn ;
Never = '!' ; Never = '!' ;
Empty = '(' ')' ; Empty = '(' ')' ;
TypeTuple = '(' (TypeExpr ',')* TypeExpr? ')' ; TyTuple = '(' (Ty ',')* Ty? ')' ;
TyRef = ('&' | '&&')* Path ;
PathExpr = '::'? PathPart ; TyFn = "fn" TyTuple (-> Ty)? ;
PathPart = "super" | Identifier ;
(* # Expressions *) (* path *)
(* expression *) Path = '::'? PathPart ('::' PathPart)* ;
PathPart = "super" | "self" | Identifier ;
Identifier = IDENTIFIER ;
(* literal *)
Bool = "true" | "false" ;
(* expr *)
ExprKind = Assign | Compare | Range | Logic | Bitwise | Shift
| Factor | Term | Unary | Member | Call | Index
| Path | Literal | Array | ArrayRep | AddrOf
| Block | Group
| While | If | For | Break | Return | Continue ;
Expr = Assign ; Expr = Assign ;
Block = '{' Stmt* Expr? '}' ;
Primary = Identifier | Literal
| Block | Group | Branch ;
(* expression::call *) Assign = Path (AssignOp Assign ) | Compare ;
Call = FnCall | Primary ;
FnCall = Primary ('(' Tuple? ')')? ;
(* expression::tuple *) Binary = Compare | Range | Logic | Bitwise | Shift | Factor | Term ;
Group = '(' Tuple? ')' ;
Tuple = Expr (',' Expr)* ;
(* expression::math *)
Assign = Identifier (AssignOp Assign) | Compare ;
Compare = Range (CompareOp Range )* ; Compare = Range (CompareOp Range )* ;
Range = Logic (RangeOp Logic )* ; Range = Logic (RangeOp Logic )* ;
Logic = Bitwise (LogicOp Bitwise)* ; Logic = Bitwise (LogicOp Bitwise)* ;
Bitwise = Shift (BitwiseOp Shift )* ; Bitwise = Shift (BitwiseOp Shift )* ;
Shift = Term (ShiftOp Term )* ; Shift = Factor (ShiftOp Factor )* ;
Term = Factor (TermOp Factor )* ; Factor = Term (FactorOp Term )* ;
Factor = Unary (FactorOp Unary )* ; Term = Unary (FactorOp Unary )* ;
Unary = (UnaryOp)* Call ;
(* expression::math::operator *) Unary = (UnaryOp)* Member ;
AssignOp = '=' | "+=" | "-=" | "*=" | "/=" |
"&=" | "|=" | "^=" |"<<=" |">>=" ;
CompareOp = '<' | "<=" | "==" | "!=" | ">=" | '>' ;
RangeOp = ".." | "..=" ;
LogicOp = "&&" | "||" | "^^" ;
BitwiseOp = '&' | '|' | '^' ; Member = Call ('.' Call)* ;
ShiftOp = "<<" | ">>";
TermOp = '+' | '-' ;
FactorOp = '*' | '/' | '%' ;
UnaryOp = '*' | '&' | '-' | '!' ;
(* expression::control *) Call = Index ('(' Tuple? ')')* ;
Branch = While | If | For | Break | Return | Continue ;
If = "if" Expr Block (Else)? ; Index = Primary ('[' Indices ']')* ;
While = "while" Expr Block (Else)? ; Indices = (Expr ',')* Expr? ;
For = "for" Identifier "in" Expr Block (Else)? ;
Primary = Literal | Path | Array | ArrayRep | AddrOf
| Block | Group
| If | While | For | Break | Return | Continue;
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
Array = '[' (Expr ',')* Expr? ']' ;
ArrayRep = '[' Expr ';' Expr ']' ;
AddrOf = ('&' | '&&')* Expr ;
Block = '{' Stmt* '}';
Group = '(' (Empty | Expr | Tuple) ')' ;
Tuple = (Expr ',')* Expr? ;
Empty = ;
While = "while" Expr Block Else? ;
If = "if" Expr Block Else? ;
For = "for" Identifier "in" Expr Block Else? ;
Else = "else" Expr ; Else = "else" Expr ;
Break = "break" Expr ; Break = "break" Expr ;
Return = "return" Expr ; Return = "return" Expr ;
Continue = "continue" ; Continue = "continue" ;
AssignKind = '=' | '+=' | '-=' | '*=' | '/=' |
'&=' | '|=' | '^=' |'<<=' |'>>=' ;
BinaryKind = CompareOp | RangeOp | LogicOp | BitwiseOp
| ShiftOp | TermOp | FactorOp ;
CompareOp = '<' | '<=' | '==' | '!=' | '>=' | '>' ;
RangeOp = '..' | '..=' ;
LogicOp = '&&' | '||' | '^^' ;
BitwiseOp = '&' | '|' | '^' ;
ShiftOp = '<<' | '>>';
TermOp = '+' | '-' ;
FactorOp = '*' | '/' | '%' ;
UnaryKind = '*' | '-' | '!' | '@' | '#' | '~' ;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,744 @@
//! Implementations of AST nodes and traits
use super::*;
mod display {
//! Implements [Display] for [AST](super::super) Types
use super::*;
pub use delimiters::*;
use std::fmt::{Display, Write};
mod delimiters {
#![allow(dead_code)]
#[derive(Clone, Copy, Debug)]
pub struct Delimiters<'t> {
pub open: &'t str,
pub close: &'t str,
}
/// Delimits with braces on separate lines `{\n`, ..., `\n}`
pub const BRACES: Delimiters = Delimiters { open: "{\n", close: "\n}" };
/// Delimits with parentheses on separate lines `{\n`, ..., `\n}`
pub const PARENS: Delimiters = Delimiters { open: "(\n", close: "\n)" };
/// Delimits with square brackets on separate lines `{\n`, ..., `\n}`
pub const SQUARE: Delimiters = Delimiters { open: "[\n", close: "\n]" };
/// Delimits with braces on the same line `{ `, ..., ` }`
pub const INLINE_BRACES: Delimiters = Delimiters { open: "{ ", close: " }" };
/// Delimits with parentheses on the same line `( `, ..., ` )`
pub const INLINE_PARENS: Delimiters = Delimiters { open: "(", close: ")" };
/// Delimits with square brackets on the same line `[ `, ..., ` ]`
pub const INLINE_SQUARE: Delimiters = Delimiters { open: "[", close: "]" };
}
fn delimit<'a>(
func: impl Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result + 'a,
delim: Delimiters<'a>,
) -> impl Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result + 'a {
move |f| {
write!(f, "{}", delim.open)?;
func(f)?;
write!(f, "{}", delim.close)
}
}
fn separate<'iterable, I>(
iterable: &'iterable [I],
sep: impl Display + 'iterable,
) -> impl Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result + 'iterable
where
I: Display,
{
move |f| {
for (idx, item) in iterable.iter().enumerate() {
if idx > 0 {
write!(f, "{sep}")?;
}
item.fmt(f)?;
}
Ok(())
}
}
impl Display for Loc {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Loc { line, col } = self;
write!(f, "{line}:{col}:")
}
}
impl Display for Mutability {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Mutability::Not => Ok(()),
Mutability::Mut => "mut ".fmt(f),
}
}
}
impl Display for Visibility {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Visibility::Private => Ok(()),
Visibility::Public => "pub ".fmt(f),
}
}
}
impl Display for File {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
separate(&self.items, "\n")(f)
}
}
impl Display for Item {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.vis.fmt(f)?;
match &self.kind {
ItemKind::Const(v) => v.fmt(f),
ItemKind::Static(v) => v.fmt(f),
ItemKind::Module(v) => v.fmt(f),
ItemKind::Function(v) => v.fmt(f),
ItemKind::Struct(v) => v.fmt(f),
ItemKind::Enum(v) => v.fmt(f),
ItemKind::Impl(v) => v.fmt(f),
}
}
}
impl Display for Const {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, ty, init } = self;
write!(f, "const {name}: {ty} = {init}")
}
}
impl Display for Static {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { mutable, name, ty, init } = self;
write!(f, "static {mutable}{name}: {ty} = {init}")
}
}
impl Display for Module {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, kind } = self;
write!(f, "mod {name}{kind}")
}
}
impl Display for ModuleKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ModuleKind::Inline(items) => {
' '.fmt(f)?;
delimit(|f| items.fmt(f), BRACES)(f)
}
ModuleKind::Outline => ';'.fmt(f),
}
}
}
impl Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, args, body, rety } = self;
write!(f, "fn {name} ")?;
delimit(separate(args, ", "), INLINE_PARENS)(f)?;
if let Some(rety) = rety {
write!(f, " -> {rety}")?;
}
match body {
Some(body) => write!(f, " {body}"),
None => ';'.fmt(f),
}
}
}
impl Display for Param {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { mutability, name, ty } = self;
write!(f, "{mutability}{name}: {ty}")
}
}
impl Display for Struct {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, kind } = self;
write!(f, "struct {name}{kind}")
}
}
impl Display for StructKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StructKind::Empty => ';'.fmt(f),
StructKind::Tuple(v) => delimit(separate(v, ", "), INLINE_PARENS)(f),
StructKind::Struct(v) => {
delimit(separate(v, ",\n"), Delimiters { open: " {\n", ..BRACES })(f)
}
}
}
}
impl Display for StructMember {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { vis, name, ty } = self;
write!(f, "{vis}{name}: {ty}")
}
}
impl Display for Enum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, kind } = self;
write!(f, "enum {name}{kind}")
}
}
impl Display for EnumKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EnumKind::NoVariants => todo!(),
EnumKind::Variants(v) => separate(v, ", ")(f),
}
}
}
impl Display for Variant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { name, kind } = self;
write!(f, "{name}{kind}")
}
}
impl Display for VariantKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VariantKind::Named(n) => n.fmt(f),
VariantKind::Tuple(v) => delimit(separate(v, ", "), INLINE_PARENS)(f),
VariantKind::Struct(v) => delimit(separate(v, ",\n"), BRACES)(f),
}
}
}
impl Display for Impl {
fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
todo!("impl Display for Impl")
}
}
impl Display for Ty {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.kind {
TyKind::Never => "!".fmt(f),
TyKind::Empty => "()".fmt(f),
TyKind::Path(v) => v.fmt(f),
TyKind::Tuple(v) => v.fmt(f),
TyKind::Ref(v) => v.fmt(f),
TyKind::Fn(v) => v.fmt(f),
}
}
}
impl Display for TyTuple {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
delimit(separate(&self.types, ", "), INLINE_PARENS)(f)
}
}
impl Display for TyRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { count: _, to } = self;
for _ in 0..self.count {
f.write_char('&')?;
}
write!(f, "{to}")
}
}
impl Display for TyFn {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { args, rety } = self;
write!(f, "fn {args}")?;
match rety {
Some(v) => write!(f, " -> {v}"),
None => Ok(()),
}
}
}
impl Display for Stmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Stmt { extents: _, kind, semi } = self;
match kind {
StmtKind::Empty => Ok(()),
StmtKind::Local(v) => v.fmt(f),
StmtKind::Item(v) => v.fmt(f),
StmtKind::Expr(v) => v.fmt(f),
}?;
match semi {
Semi::Terminated => ';'.fmt(f),
Semi::Unterminated => Ok(()),
}
}
}
impl Display for Let {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { mutable, name, init } = self;
write!(f, "let {mutable}{name}")?;
if let Some(value) = init {
write!(f, " = {value}")?;
}
Ok(())
}
}
impl Display for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.kind {
ExprKind::Assign(v) => v.fmt(f),
ExprKind::Binary(v) => v.fmt(f),
ExprKind::Unary(v) => v.fmt(f),
ExprKind::Index(v) => v.fmt(f),
ExprKind::Call(v) => v.fmt(f),
ExprKind::Member(v) => v.fmt(f),
ExprKind::Path(v) => v.fmt(f),
ExprKind::Literal(v) => v.fmt(f),
ExprKind::Array(v) => v.fmt(f),
ExprKind::ArrayRep(v) => v.fmt(f),
ExprKind::AddrOf(v) => v.fmt(f),
ExprKind::Block(v) => v.fmt(f),
ExprKind::Empty => "()".fmt(f),
ExprKind::Group(v) => v.fmt(f),
ExprKind::Tuple(v) => v.fmt(f),
ExprKind::While(v) => v.fmt(f),
ExprKind::If(v) => v.fmt(f),
ExprKind::For(v) => v.fmt(f),
ExprKind::Break(v) => v.fmt(f),
ExprKind::Return(v) => v.fmt(f),
ExprKind::Continue(_) => "continue".fmt(f),
}
}
}
impl Display for Assign {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { head, op, tail } = self;
write!(f, "{head} {op} {tail}")
}
}
impl Display for AssignKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AssignKind::Plain => "=",
AssignKind::Mul => "*=",
AssignKind::Div => "/=",
AssignKind::Rem => "%=",
AssignKind::Add => "+=",
AssignKind::Sub => "-=",
AssignKind::And => "&=",
AssignKind::Or => "|=",
AssignKind::Xor => "^=",
AssignKind::Shl => "<<=",
AssignKind::Shr => ">>=",
}
.fmt(f)
}
}
impl Display for Binary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { head, tail } = self;
write!(f, "{head}")?;
for (kind, expr) in tail {
write!(f, " {kind} {expr}")?;
}
Ok(())
}
}
impl Display for BinaryKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BinaryKind::Lt => "<",
BinaryKind::LtEq => "<=",
BinaryKind::Equal => "==",
BinaryKind::NotEq => "!=",
BinaryKind::GtEq => ">=",
BinaryKind::Gt => ">",
BinaryKind::RangeExc => "..",
BinaryKind::RangeInc => "..=",
BinaryKind::LogAnd => "&&",
BinaryKind::LogOr => "||",
BinaryKind::LogXor => "^^",
BinaryKind::BitAnd => "&",
BinaryKind::BitOr => "|",
BinaryKind::BitXor => "^",
BinaryKind::Shl => "<<",
BinaryKind::Shr => ">>",
BinaryKind::Add => "+",
BinaryKind::Sub => "-",
BinaryKind::Mul => "*",
BinaryKind::Div => "/",
BinaryKind::Rem => "%",
BinaryKind::Dot => ".",
}
.fmt(f)
}
}
impl Display for Unary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { ops: kinds, tail } = self;
for kind in kinds {
kind.fmt(f)?
}
tail.fmt(f)
}
}
impl Display for UnaryKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
UnaryKind::Deref => "*",
UnaryKind::Neg => "-",
UnaryKind::Not => "!",
UnaryKind::At => "@",
UnaryKind::Hash => "#",
UnaryKind::Tilde => "~",
}
.fmt(f)
}
}
impl Display for Call {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { callee, args } = self;
callee.fmt(f)?;
for args in args {
args.fmt(f)?;
}
Ok(())
}
}
impl Display for Tuple {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
delimit(separate(&self.exprs, ", "), INLINE_PARENS)(f)
}
}
impl Display for Member {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { head: parent, tail: children } = self;
write!(f, "{parent}.")?;
separate(children, ".")(f)?;
Ok(())
}
}
impl Display for Index {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { head, indices } = self;
write!(f, "{head}")?;
for indices in indices {
indices.fmt(f)?;
}
Ok(())
}
}
impl Display for Indices {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
delimit(separate(&self.exprs, ", "), INLINE_SQUARE)(f)
}
}
impl Display for Path {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { absolute, parts } = self;
if *absolute {
"::".fmt(f)?;
}
separate(parts, "::")(f)
}
}
impl Display for PathPart {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PathPart::SuperKw => "super".fmt(f),
PathPart::SelfKw => "self".fmt(f),
PathPart::Ident(id) => id.fmt(f),
}
}
}
impl Display for Identifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl Display for Literal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Literal::Bool(v) => v.fmt(f),
Literal::Char(v) => write!(f, "'{v}'"),
Literal::Int(v) => v.fmt(f),
Literal::String(v) => write!(f, "\"{v}\""),
}
}
}
impl Display for Array {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
delimit(separate(&self.values, ", "), INLINE_SQUARE)(f)
}
}
impl Display for ArrayRep {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { value, repeat } = self;
write!(f, "[{value}; {repeat}]")
}
}
impl Display for AddrOf {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { count, mutable, expr } = self;
for _ in 0..*count {
f.write_char('&')?;
}
write!(f, "{mutable}{expr}")
}
}
impl Display for Block {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
delimit(separate(&self.stmts, "\n"), BRACES)(f)
}
}
impl Display for Group {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({})", self.expr)
}
}
impl Display for While {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { cond, pass, fail } = self;
write!(f, "while {cond} {pass}{fail}")
}
}
impl Display for If {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { cond, pass, fail } = self;
write!(f, "if {cond} {pass}{fail}")
}
}
impl Display for For {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { bind, cond, pass, fail } = self;
write!(f, "for {bind} in {cond} {pass}{fail}")
}
}
impl Display for Else {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.body {
Some(body) => write!(f, " else {body}"),
_ => Ok(()),
}
}
}
impl Display for Break {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "break")?;
match &self.body {
Some(body) => write!(f, " {body}"),
_ => Ok(()),
}
}
}
impl Display for Return {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "return")?;
match &self.body {
Some(body) => write!(f, " {body}"),
_ => Ok(()),
}
}
}
}
pub mod format {
//! Code formatting for the [AST](super::super)
use std::{
io::{Result, Write as IoWrite},
ops::{Deref, DerefMut},
};
/// Trait which adds a function to [Writers](IoWrite) to turn them into [Prettifier]
pub trait Pretty {
/// Indents code according to the number of matched curly braces
fn pretty(self) -> Prettifier<'static, Self>
where Self: IoWrite + Sized;
}
impl<W: IoWrite> Pretty for W {
fn pretty(self) -> Prettifier<'static, Self>
where Self: IoWrite + Sized {
Prettifier::new(self)
}
}
pub struct Prettifier<'i, T: IoWrite> {
level: isize,
indent: &'i str,
writer: T,
}
impl<'i, W: IoWrite> Prettifier<'i, W> {
pub fn new(writer: W) -> Self {
Self { level: 0, indent: " ", writer }
}
pub fn with_indent(indent: &'i str, writer: W) -> Self {
Self { level: 0, indent, writer }
}
pub fn indent<'scope>(&'scope mut self) -> Indent<'scope, 'i, W> {
Indent::new(self)
}
fn write_indentation(&mut self) -> Result<usize> {
let Self { level, indent, writer } = self;
let mut count = 0;
for _ in 0..*level {
count += writer.write(indent.as_bytes())?;
}
Ok(count)
}
}
impl<W: IoWrite> From<W> for Prettifier<'static, W> {
fn from(value: W) -> Self {
Self::new(value)
}
}
impl<'i, W: IoWrite> IoWrite for Prettifier<'i, W> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut size = 0;
for buf in buf.split_inclusive(|b| b"{}".contains(b)) {
match buf.last() {
Some(b'{') => self.level += 1,
Some(b'}') => self.level -= 1,
_ => (),
}
for buf in buf.split_inclusive(|b| b'\n' == *b) {
size += self.writer.write(buf)?;
if let Some(b'\n') = buf.last() {
self.write_indentation()?;
}
}
}
Ok(size)
}
fn flush(&mut self) -> std::io::Result<()> {
self.writer.flush()
}
}
pub struct Indent<'scope, 'i, T: IoWrite> {
formatter: &'scope mut Prettifier<'i, T>,
}
impl<'s, 'i, T: IoWrite> Indent<'s, 'i, T> {
pub fn new(formatter: &'s mut Prettifier<'i, T>) -> Self {
formatter.level += 1;
Self { formatter }
}
}
impl<'s, 'i, T: IoWrite> Deref for Indent<'s, 'i, T> {
type Target = Prettifier<'i, T>;
fn deref(&self) -> &Self::Target {
self.formatter
}
}
impl<'s, 'i, T: IoWrite> DerefMut for Indent<'s, 'i, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.formatter
}
}
impl<'s, 'i, T: IoWrite> Drop for Indent<'s, 'i, T> {
fn drop(&mut self) {
self.formatter.level -= 1;
}
}
}
mod convert {
//! Converts between major enums and enum variants
use super::*;
use crate::lexer::Lexer;
impl<T: AsRef<str>> From<T> for Identifier {
fn from(value: T) -> Self {
Identifier(value.as_ref().into())
}
}
macro impl_from ($(impl From for $T:ty {$($from:ty => $to:expr),*$(,)?})*) {$($(
impl From<$from> for $T {
fn from(value: $from) -> Self {
$to(value.into()) // Uses *tuple constructor*
}
}
impl From<Box<$from>> for $T {
fn from(value: Box<$from>) -> Self {
$to((*value).into())
}
}
)*)*}
impl_from! {
impl From for ItemKind {
Const => ItemKind::Const,
Static => ItemKind::Static,
Module => ItemKind::Module,
Function => ItemKind::Function,
Struct => ItemKind::Struct,
Enum => ItemKind::Enum,
Impl => ItemKind::Impl,
}
impl From for StructKind {
Vec<Ty> => StructKind::Tuple,
// TODO: Struct members in struct
}
impl From for EnumKind {
Vec<Variant> => EnumKind::Variants,
}
impl From for VariantKind {
Identifier => VariantKind::Named,
Vec<Ty> => VariantKind::Tuple,
// TODO: enum struct variants
}
impl From for TyKind {
Path => TyKind::Path,
TyTuple => TyKind::Tuple,
TyRef => TyKind::Ref,
TyFn => TyKind::Fn,
}
impl From for StmtKind {
Let => StmtKind::Local,
Item => StmtKind::Item,
// NOTE: There are multiple conversions from Expr to StmtKind
}
impl From for ExprKind {
Assign => ExprKind::Assign,
Binary => ExprKind::Binary,
Unary => ExprKind::Unary,
Call => ExprKind::Call,
Member => ExprKind::Member,
Index => ExprKind::Index,
Path => ExprKind::Path,
Literal => ExprKind::Literal,
Array => ExprKind::Array,
ArrayRep => ExprKind::ArrayRep,
AddrOf => ExprKind::AddrOf,
Block => ExprKind::Block,
Group => ExprKind::Group,
Tuple => ExprKind::Tuple,
While => ExprKind::While,
If => ExprKind::If,
For => ExprKind::For,
Break => ExprKind::Break,
Return => ExprKind::Return,
Continue => ExprKind::Continue,
}
impl From for Literal {
bool => Literal::Bool,
char => Literal::Char,
u128 => Literal::Int,
&str => Literal::String,
}
}
impl From<Tuple> for Indices {
fn from(value: Tuple) -> Self {
Self { exprs: value.exprs }
}
}
impl From<Indices> for Tuple {
fn from(value: Indices) -> Self {
Self { exprs: value.exprs }
}
}
impl From<Option<Expr>> for Else {
fn from(value: Option<Expr>) -> Self {
Self { body: value.map(Into::into) }
}
}
impl From<Expr> for Else {
fn from(value: Expr) -> Self {
Self { body: Some(value.into()) }
}
}
impl<'t> From<&Lexer<'t>> for Loc {
fn from(value: &Lexer<'t>) -> Self {
Self { line: value.line(), col: value.col() }
}
}
}

View File

@ -1,8 +1,8 @@
//! Interprets an AST as a program //! Interprets an AST as a program
use crate::ast::preamble::*;
use env::Environment; use env::Environment;
use error::{Error, IResult}; use error::{Error, IResult};
use interpret::Interpret;
use temp_type_impl::ConValue; use temp_type_impl::ConValue;
/// Callable types can be called from within a Conlang program /// Callable types can be called from within a Conlang program
@ -44,6 +44,8 @@ pub mod temp_type_impl {
Char(char), Char(char),
/// A string /// A string
String(String), String(String),
/// An Array
Array(Vec<ConValue>),
/// A tuple /// A tuple
Tuple(Vec<ConValue>), Tuple(Vec<ConValue>),
/// An exclusive range /// An exclusive range
@ -75,6 +77,17 @@ pub mod temp_type_impl {
}; };
Ok(Self::RangeInc(a, b)) Ok(Self::RangeInc(a, b))
} }
pub fn index(&self, index: &Self) -> IResult<ConValue> {
let Self::Int(index) = index else {
Err(Error::TypeError)?
};
let Self::Array(arr) = self else {
Err(Error::TypeError)?
};
arr.get(*index as usize)
.cloned()
.ok_or(Error::OobIndex(*index as usize, arr.len()))
}
cmp! { cmp! {
lt: false, <; lt: false, <;
lt_eq: true, <=; lt_eq: true, <=;
@ -259,6 +272,16 @@ pub mod temp_type_impl {
ConValue::Bool(v) => v.fmt(f), ConValue::Bool(v) => v.fmt(f),
ConValue::Char(v) => v.fmt(f), ConValue::Char(v) => v.fmt(f),
ConValue::String(v) => v.fmt(f), ConValue::String(v) => v.fmt(f),
ConValue::Array(array) => {
'['.fmt(f)?;
for (idx, element) in array.iter().enumerate() {
if idx > 0 {
", ".fmt(f)?
}
element.fmt(f)?
}
']'.fmt(f)
}
ConValue::RangeExc(a, b) => write!(f, "{a}..{}", b + 1), ConValue::RangeExc(a, b) => write!(f, "{a}..{}", b + 1),
ConValue::RangeInc(a, b) => write!(f, "{a}..={b}"), ConValue::RangeInc(a, b) => write!(f, "{a}..={b}"),
ConValue::Tuple(tuple) => { ConValue::Tuple(tuple) => {
@ -282,6 +305,9 @@ pub mod temp_type_impl {
} }
} }
pub mod interpret {
use super::*;
use crate::ast::*;
/// A work-in-progress tree walk interpreter for Conlang /// A work-in-progress tree walk interpreter for Conlang
pub trait Interpret { pub trait Interpret {
/// Interprets this thing in the given [`Environment`]. /// Interprets this thing in the given [`Environment`].
@ -290,32 +316,86 @@ pub trait Interpret {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue>; fn interpret(&self, env: &mut Environment) -> IResult<ConValue>;
} }
impl Interpret for Start { impl Interpret for File {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
self.0.interpret(env) for item in &self.items {
item.interpret(env)?;
}
Ok(ConValue::Empty)
} }
} }
impl Interpret for Program { impl Interpret for Item {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let mut out = ConValue::Empty; match &self.kind {
for stmt in &self.0 { ItemKind::Const(item) => item.interpret(env),
out = stmt.interpret(env)?; ItemKind::Static(item) => item.interpret(env),
ItemKind::Module(item) => item.interpret(env),
ItemKind::Function(item) => item.interpret(env),
ItemKind::Struct(item) => item.interpret(env),
ItemKind::Enum(item) => item.interpret(env),
ItemKind::Impl(item) => item.interpret(env),
} }
Ok(out) }
}
impl Interpret for Const {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
todo!("interpret const in {env}")
}
}
impl Interpret for Static {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
todo!("interpret static in {env}")
}
}
impl Interpret for Module {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
// TODO: Enter this module's namespace
match &self.kind {
ModuleKind::Inline(file) => file.interpret(env),
ModuleKind::Outline => todo!("Load and parse external files"),
}
}
}
impl Interpret for Function {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
// register the function in the current environment
env.insert_fn(self);
Ok(ConValue::Empty)
}
}
impl Interpret for Struct {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
todo!("Interpret structs in {env}")
}
}
impl Interpret for Enum {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
todo!("Interpret enums in {env}")
}
}
impl Interpret for Impl {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
todo!("Enter a struct's namespace and insert function definitions into it in {env}");
} }
} }
impl Interpret for Stmt { impl Interpret for Stmt {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self { let Self { extents: _, kind, semi } = self;
Stmt::Let(l) => l.interpret(env), let out = match kind {
Stmt::Fn(f) => f.interpret(env), StmtKind::Empty => ConValue::Empty,
Stmt::Expr(e) => e.interpret(env), StmtKind::Local(stmt) => stmt.interpret(env)?,
} StmtKind::Item(stmt) => stmt.interpret(env)?,
StmtKind::Expr(stmt) => stmt.interpret(env)?,
};
Ok(match semi {
Semi::Terminated => ConValue::Empty,
Semi::Unterminated => out,
})
} }
} }
impl Interpret for Let { impl Interpret for Let {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Let { name: Name { symbol: Identifier { name, .. }, .. }, init, .. } = self; let Let { mutable: _, name: Identifier(name), init } = self;
if let Some(init) = init { if let Some(init) = init {
let init = init.interpret(env)?; let init = init.interpret(env)?;
env.insert(name, Some(init)); env.insert(name, Some(init));
@ -325,36 +405,60 @@ impl Interpret for Let {
Ok(ConValue::Empty) Ok(ConValue::Empty)
} }
} }
impl Interpret for FnDecl {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
// register the function in the current environment
env.insert_fn(self);
Ok(ConValue::Empty)
}
}
impl Interpret for Expr { impl Interpret for Expr {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
self.0.interpret(env) let Self { extents: _, kind } = self;
} match kind {
} ExprKind::Assign(v) => v.interpret(env),
impl Interpret for Operation { ExprKind::Binary(v) => v.interpret(env),
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { ExprKind::Unary(v) => v.interpret(env),
match self { ExprKind::Member(v) => v.interpret(env),
Operation::Assign(op) => op.interpret(env), ExprKind::Call(v) => v.interpret(env),
Operation::Binary(op) => op.interpret(env), ExprKind::Index(v) => v.interpret(env),
Operation::Unary(op) => op.interpret(env), ExprKind::Path(v) => v.interpret(env),
Operation::Call(op) => op.interpret(env), ExprKind::Literal(v) => v.interpret(env),
ExprKind::Array(v) => v.interpret(env),
ExprKind::ArrayRep(v) => v.interpret(env),
ExprKind::AddrOf(v) => v.interpret(env),
ExprKind::Block(v) => v.interpret(env),
ExprKind::Empty => Ok(ConValue::Empty),
ExprKind::Group(v) => v.interpret(env),
ExprKind::Tuple(v) => v.interpret(env),
ExprKind::While(v) => v.interpret(env),
ExprKind::If(v) => v.interpret(env),
ExprKind::For(v) => v.interpret(env),
ExprKind::Break(v) => v.interpret(env),
ExprKind::Return(v) => v.interpret(env),
ExprKind::Continue(v) => v.interpret(env),
} }
} }
} }
impl Interpret for Assign { impl Interpret for Assign {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
use operator::Assign; let Assign { head, op, tail } = self;
let math::Assign { target: Identifier { name, .. }, operator, init } = self; // Resolve the head pattern
let init = init.interpret(env)?; let head = match &head.kind {
let target = env.get_mut(name)?; ExprKind::Path(Path { parts, .. }) if parts.len() == 1 => {
match parts.last().expect("parts should not be empty") {
PathPart::SuperKw => Err(Error::NotAssignable(head.extents.head))?,
PathPart::SelfKw => todo!("Assignment to `self`"),
PathPart::Ident(Identifier(s)) => s,
}
}
ExprKind::Member(_) => todo!("Member access assignment"),
ExprKind::Call(_) => todo!("Assignment to the result of a function call?"),
ExprKind::Index(_) => todo!("Assignment to an index operation"),
ExprKind::Path(_) => todo!("Path expression resolution (IMPORTANT)"),
ExprKind::Empty | ExprKind::Group(_) | ExprKind::Tuple(_) => {
todo!("Pattern Destructuring?")
}
_ => Err(Error::NotAssignable(head.extents.head))?,
};
// Get the initializer and the tail
let init = tail.interpret(env)?;
let target = env.get_mut(head)?;
if let Assign::Assign = operator { if let AssignKind::Plain = op {
use std::mem::discriminant as variant; use std::mem::discriminant as variant;
// runtime typecheck // runtime typecheck
match target { match target {
@ -367,20 +471,20 @@ impl Interpret for Assign {
return Ok(ConValue::Empty); return Ok(ConValue::Empty);
} }
let Some(target) = target else { let Some(target) = target else {
return Err(Error::NotInitialized(name.into())); return Err(Error::NotInitialized(head.into()));
}; };
match operator { match op {
Assign::AddAssign => target.add_assign(init)?, AssignKind::Add => target.add_assign(init)?,
Assign::SubAssign => target.sub_assign(init)?, AssignKind::Sub => target.sub_assign(init)?,
Assign::MulAssign => target.mul_assign(init)?, AssignKind::Mul => target.mul_assign(init)?,
Assign::DivAssign => target.div_assign(init)?, AssignKind::Div => target.div_assign(init)?,
Assign::RemAssign => target.rem_assign(init)?, AssignKind::Rem => target.rem_assign(init)?,
Assign::BitAndAssign => target.bitand_assign(init)?, AssignKind::And => target.bitand_assign(init)?,
Assign::BitOrAssign => target.bitor_assign(init)?, AssignKind::Or => target.bitor_assign(init)?,
Assign::BitXorAssign => target.bitxor_assign(init)?, AssignKind::Xor => target.bitxor_assign(init)?,
Assign::ShlAssign => target.shl_assign(init)?, AssignKind::Shl => target.shl_assign(init)?,
Assign::ShrAssign => target.shr_assign(init)?, AssignKind::Shr => target.shr_assign(init)?,
_ => (), _ => (),
} }
Ok(ConValue::Empty) Ok(ConValue::Empty)
@ -388,89 +492,87 @@ impl Interpret for Assign {
} }
impl Interpret for Binary { impl Interpret for Binary {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Binary { first, other } = self; let Binary { head, tail } = self;
let mut first = first.interpret(env)?; let mut head = head.interpret(env)?;
for (op, other) in other { for (op, tail) in tail {
first = match op { head = match op {
operator::Binary::LogAnd => { BinaryKind::LogAnd => {
if first.truthy()? { if head.truthy()? {
other.interpret(env) tail.interpret(env)
} else { } else {
return Ok(first); // Short circuiting return Ok(head); // Short circuiting
} }
} }
operator::Binary::LogOr => { BinaryKind::LogOr => {
if !first.truthy()? { if !head.truthy()? {
other.interpret(env) tail.interpret(env)
} else { } else {
return Ok(first); // Short circuiting return Ok(head); // Short circuiting
} }
} }
operator::Binary::LogXor => { BinaryKind::LogXor => {
// TODO: It should be possible to assemble better error information from this // TODO: It should be possible to assemble better error information from
let (lhs, rhs) = (first.truthy()?, other.interpret(env)?.truthy()?); // this
let (lhs, rhs) = (head.truthy()?, tail.interpret(env)?.truthy()?);
Ok(ConValue::Bool(lhs ^ rhs)) Ok(ConValue::Bool(lhs ^ rhs))
} }
// TODO: For all overloadable operators, transmute into function call // TODO: For all overloadable operators, transmute into function call
operator::Binary::Mul => first * other.interpret(env)?, BinaryKind::Mul => head * tail.interpret(env)?,
operator::Binary::Div => first / other.interpret(env)?, BinaryKind::Div => head / tail.interpret(env)?,
operator::Binary::Rem => first % other.interpret(env)?, BinaryKind::Rem => head % tail.interpret(env)?,
operator::Binary::Add => first + other.interpret(env)?, BinaryKind::Add => head + tail.interpret(env)?,
operator::Binary::Sub => first - other.interpret(env)?, BinaryKind::Sub => head - tail.interpret(env)?,
operator::Binary::Lsh => first << other.interpret(env)?, BinaryKind::Shl => head << tail.interpret(env)?,
operator::Binary::Rsh => first >> other.interpret(env)?, BinaryKind::Shr => head >> tail.interpret(env)?,
operator::Binary::BitAnd => first & other.interpret(env)?, BinaryKind::BitAnd => head & tail.interpret(env)?,
operator::Binary::BitOr => first | other.interpret(env)?, BinaryKind::BitOr => head | tail.interpret(env)?,
operator::Binary::BitXor => first ^ other.interpret(env)?, BinaryKind::BitXor => head ^ tail.interpret(env)?,
operator::Binary::RangeExc => first.range_exc(other.interpret(env)?), BinaryKind::RangeExc => head.range_exc(tail.interpret(env)?),
operator::Binary::RangeInc => first.range_inc(other.interpret(env)?), BinaryKind::RangeInc => head.range_inc(tail.interpret(env)?),
operator::Binary::Less => first.lt(&other.interpret(env)?), BinaryKind::Lt => head.lt(&tail.interpret(env)?),
operator::Binary::LessEq => first.lt_eq(&other.interpret(env)?), BinaryKind::LtEq => head.lt_eq(&tail.interpret(env)?),
operator::Binary::Equal => first.eq(&other.interpret(env)?), BinaryKind::Equal => head.eq(&tail.interpret(env)?),
operator::Binary::NotEq => first.neq(&other.interpret(env)?), BinaryKind::NotEq => head.neq(&tail.interpret(env)?),
operator::Binary::GreaterEq => first.gt_eq(&other.interpret(env)?), BinaryKind::GtEq => head.gt_eq(&tail.interpret(env)?),
operator::Binary::Greater => first.gt(&other.interpret(env)?), BinaryKind::Gt => head.gt(&tail.interpret(env)?),
BinaryKind::Dot => todo!("search within a type's namespace!"),
}?; }?;
} }
Ok(first) Ok(head)
} }
} }
impl Interpret for Unary { impl Interpret for Unary {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Unary { operand, operators } = self; let Unary { tail, ops } = self;
let mut operand = operand.interpret(env)?; let mut operand = tail.interpret(env)?;
for op in operators.iter().rev() { for op in ops.iter().rev() {
operand = match op { operand = match op {
operator::Unary::RefRef => todo!(), UnaryKind::Deref => todo!("Deref operator"),
operator::Unary::Ref => todo!(), UnaryKind::Neg => (-operand)?,
operator::Unary::Deref => todo!(), UnaryKind::Not => (!operand)?,
operator::Unary::Neg => (-operand)?, UnaryKind::At => unimplemented!("At operator"),
operator::Unary::Not => (!operand)?, UnaryKind::Hash => {
operator::Unary::At => todo!(),
operator::Unary::Hash => {
println!("{operand}"); println!("{operand}");
operand operand
} }
operator::Unary::Tilde => todo!(), UnaryKind::Tilde => unimplemented!("Tilde operator"),
}; };
} }
Ok(operand) Ok(operand)
} }
} }
impl Interpret for Member {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
todo!("Interpret member accesses in {env}")
}
}
impl Interpret for Call { impl Interpret for Call {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self { let Self { callee, args } = self;
Call::FnCall(fncall) => fncall.interpret(env),
Call::Primary(primary) => primary.interpret(env),
}
}
}
impl Interpret for FnCall {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
// evaluate the callee // evaluate the callee
let mut callee = self.callee.interpret(env)?; let mut callee = callee.interpret(env)?;
for args in &self.args { for args in args {
let ConValue::Tuple(args) = args.interpret(env)? else { let ConValue::Tuple(args) = args.interpret(env)? else {
Err(Error::TypeError)? Err(Error::TypeError)?
}; };
@ -479,20 +581,31 @@ impl Interpret for FnCall {
Ok(callee) Ok(callee)
} }
} }
impl Interpret for Primary { impl Interpret for Index {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self { let Self { head, indices } = self;
Primary::Identifier(prim) => prim.interpret(env), let mut head = head.interpret(env)?;
Primary::Literal(prim) => prim.interpret(env), for indices in indices {
Primary::Block(prim) => prim.interpret(env), let Indices { exprs } = indices;
Primary::Group(prim) => prim.interpret(env), for index in exprs {
Primary::Branch(prim) => prim.interpret(env), head = head.index(&index.interpret(env)?)?;
} }
} }
Ok(head)
} }
impl Interpret for Identifier { }
impl Interpret for Path {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
env.get(&self.name).cloned() let Self { absolute: _, parts } = self;
if parts.len() == 1 {
match parts.last().expect("parts should not be empty") {
PathPart::SuperKw | PathPart::SelfKw => todo!("Path navigation"),
PathPart::Ident(Identifier(s)) => env.get(s).cloned(),
}
} else {
todo!("Path navigation!")
}
} }
} }
impl Interpret for Literal { impl Interpret for Literal {
@ -501,37 +614,69 @@ impl Interpret for Literal {
Literal::String(value) => ConValue::from(value.as_str()), Literal::String(value) => ConValue::from(value.as_str()),
Literal::Char(value) => ConValue::Char(*value), Literal::Char(value) => ConValue::Char(*value),
Literal::Bool(value) => ConValue::Bool(*value), Literal::Bool(value) => ConValue::Bool(*value),
Literal::Float(value) => todo!("Float values in interpreter: {value:?}"), // Literal::Float(value) => todo!("Float values in interpreter: {value:?}"),
Literal::Int(value) => ConValue::Int(*value as _), Literal::Int(value) => ConValue::Int(*value as _),
}) })
} }
} }
impl Interpret for Array {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { values } = self;
let mut out = vec![];
for expr in values {
out.push(expr.interpret(env)?)
}
Ok(ConValue::Array(out))
}
}
impl Interpret for ArrayRep {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { value, repeat } = self;
let repeat = match repeat.interpret(env)? {
ConValue::Int(v) => v,
_ => Err(Error::TypeError)?,
};
let value = value.interpret(env)?;
Ok(ConValue::Array(vec![value; repeat as usize]))
}
}
impl Interpret for AddrOf {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
todo!("Implement AddrOf in {env}")
}
}
impl Interpret for Block { impl Interpret for Block {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { stmts } = self;
let mut env = env.frame("block"); let mut env = env.frame("block");
// TODO: this could TOTALLY be done with a binary operator. let mut out = ConValue::Empty;
for stmt in &self.statements { for stmt in stmts {
let Stmt { kind, semi, .. } = stmt;
out = match (kind, semi) {
(StmtKind::Expr(_), Semi::Unterminated) => stmt.interpret(&mut env)?,
(StmtKind::Expr(_), _) => {
stmt.interpret(&mut env)?; stmt.interpret(&mut env)?;
ConValue::Empty
} }
if let Some(expr) = self.expr.as_ref() { _ => {
expr.interpret(&mut env) stmt.interpret(&mut env)?;
} else { continue;
Ok(ConValue::Empty)
} }
} }
} }
Ok(out)
}
}
impl Interpret for Group { impl Interpret for Group {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self { let Self { expr } = self;
Group::Tuple(tuple) => tuple.interpret(env), expr.interpret(env)
Group::Single(value) => value.interpret(env),
Group::Empty => Ok(ConValue::Empty),
}
} }
} }
impl Interpret for Tuple { impl Interpret for Tuple {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
Ok(ConValue::Tuple(self.elements.iter().try_fold( let Self { exprs } = self;
Ok(ConValue::Tuple(exprs.iter().try_fold(
vec![], vec![],
|mut out, element| { |mut out, element| {
out.push(element.interpret(env)?); out.push(element.interpret(env)?);
@ -540,71 +685,58 @@ impl Interpret for Tuple {
)?)) )?))
} }
} }
impl Interpret for Flow {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self {
Flow::While(flow) => flow.interpret(env),
Flow::If(flow) => flow.interpret(env),
Flow::For(flow) => flow.interpret(env),
Flow::Continue(flow) => flow.interpret(env),
Flow::Return(flow) => flow.interpret(env),
Flow::Break(flow) => flow.interpret(env),
}
}
}
impl Interpret for While { impl Interpret for While {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
while self.cond.interpret(env)?.truthy()? { let Self { cond, pass, fail } = self;
match self.body.interpret(env) { while cond.interpret(env)?.truthy()? {
match pass.interpret(env) {
Err(Error::Break(value)) => return Ok(value), Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue, Err(Error::Continue) => continue,
e => e?, e => e?,
}; };
} }
if let Some(other) = &self.else_ { fail.interpret(env)
other.interpret(env)
} else {
Ok(ConValue::Empty)
}
}
}
impl Interpret for Else {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
self.expr.interpret(env)
} }
} }
impl Interpret for If { impl Interpret for If {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
if self.cond.interpret(env)?.truthy()? { let Self { cond, pass, fail } = self;
self.body.interpret(env) if cond.interpret(env)?.truthy()? {
} else if let Some(other) = &self.else_ { pass.interpret(env)
other.interpret(env)
} else { } else {
Ok(ConValue::Empty) fail.interpret(env)
} }
} }
} }
impl Interpret for For { impl Interpret for For {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let bounds = match self.iter.interpret(env)? { let Self { bind: Identifier(name), cond, pass, fail } = self;
// TODO: A better iterator model
let bounds = match cond.interpret(env)? {
ConValue::RangeExc(a, b) => a..=b, ConValue::RangeExc(a, b) => a..=b,
ConValue::RangeInc(a, b) => a..=b, ConValue::RangeInc(a, b) => a..=b,
_ => Err(Error::TypeError)?, _ => Err(Error::TypeError)?,
}; };
{
let mut env = env.frame("loop variable"); let mut env = env.frame("loop variable");
for loop_var in bounds { for loop_var in bounds {
env.insert(&self.var.name, Some(loop_var.into())); env.insert(name, Some(loop_var.into()));
match self.body.interpret(&mut env) { match pass.interpret(&mut env) {
Err(Error::Break(value)) => return Ok(value), Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue, Err(Error::Continue) => continue,
result => result?, result => result?,
}; };
} }
if let Some(other) = &self.else_ { }
other.interpret(&mut env) fail.interpret(env)
} else { }
Ok(ConValue::Empty) }
impl Interpret for Else {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { body } = self;
match body {
Some(body) => body.interpret(env),
None => Ok(ConValue::Empty),
} }
} }
} }
@ -615,19 +747,30 @@ impl Interpret for Continue {
} }
impl Interpret for Return { impl Interpret for Return {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
Err(Error::Return(self.expr.interpret(env)?)) let Self { body } = self;
Err(Error::Return(
body.as_ref()
.map(|body| body.interpret(env))
.unwrap_or(Ok(ConValue::Empty))?,
))
} }
} }
impl Interpret for Break { impl Interpret for Break {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
Err(Error::Break(self.expr.interpret(env)?)) let Self { body } = self;
Err(Error::Return(
body.as_ref()
.map(|body| body.interpret(env))
.unwrap_or(Ok(ConValue::Empty))?,
))
}
} }
} }
pub mod function { pub mod function {
//! Represents a block of code which lives inside the Interpreter //! Represents a block of code which lives inside the Interpreter
use super::{Callable, ConValue, Environment, Error, FnDecl, IResult, Identifier, Interpret}; use super::{Callable, ConValue, Environment, Error, IResult, Interpret};
use crate::ast::preamble::Name; use crate::ast::{Function as FnDecl, Identifier, Param};
/// Represents a block of code which persists inside the Interpreter /// Represents a block of code which persists inside the Interpreter
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Function { pub struct Function {
@ -645,22 +788,26 @@ pub mod function {
impl Callable for Function { impl Callable for Function {
fn name(&self) -> &str { fn name(&self) -> &str {
&self.decl.name.symbol.name let FnDecl { name: Identifier(ref name), .. } = *self.decl;
name
} }
fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> { fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
let FnDecl { name: Identifier(name), args: declargs, body, rety: _ } = &*self.decl;
// Check arg mapping // Check arg mapping
if args.len() != self.decl.args.len() { if args.len() != declargs.len() {
return Err(Error::ArgNumber { want: self.decl.args.len(), got: args.len() }); return Err(Error::ArgNumber { want: declargs.len(), got: args.len() });
} }
// TODO: Isolate cross-function scopes! let Some(body) = body else {
// let mut env = self.env.clone(); return Err(Error::NotDefined(name.into()));
};
// TODO: completely refactor data storage
let mut frame = env.frame("fn args"); let mut frame = env.frame("fn args");
for (Name { symbol: Identifier { name, .. }, .. }, value) in for (Param { mutability: _, name: Identifier(name), ty: _ }, value) in
self.decl.args.iter().zip(args) declargs.iter().zip(args)
{ {
frame.insert(name, Some(value.clone())); frame.insert(name, Some(value.clone()));
} }
match self.decl.body.interpret(&mut frame) { match body.interpret(&mut frame) {
Err(Error::Return(value)) => Ok(value), Err(Error::Return(value)) => Ok(value),
Err(Error::Break(value)) => Err(Error::BadBreak(value)), Err(Error::Break(value)) => Err(Error::BadBreak(value)),
result => result, result => result,
@ -734,14 +881,14 @@ pub mod builtin {
pub mod env { pub mod env {
//! Lexical and non-lexical scoping for variables //! Lexical and non-lexical scoping for variables
use super::{ use super::{
builtin::DEFAULT_BUILTINS, builtin::DEFAULT_BUILTINS,
error::{Error, IResult}, error::{Error, IResult},
function::Function, function::Function,
temp_type_impl::ConValue, temp_type_impl::ConValue,
Callable, FnDecl, Interpret, Callable, Interpret,
}; };
use crate::ast::{Function as FnDecl, Identifier};
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::Display, fmt::Display,
@ -838,10 +985,8 @@ pub mod env {
} }
/// A convenience function for registering a [FnDecl] as a [Function] /// A convenience function for registering a [FnDecl] as a [Function]
pub fn insert_fn(&mut self, decl: &FnDecl) { pub fn insert_fn(&mut self, decl: &FnDecl) {
let (name, function) = ( let FnDecl { name: Identifier(name), .. } = decl;
decl.name.symbol.name.clone(), let (name, function) = (name.clone(), Some(Function::new(decl).into()));
Some(Function::new(decl).into()),
);
if let Some((frame, _)) = self.frames.last_mut() { if let Some((frame, _)) = self.frames.last_mut() {
frame.insert(name, function); frame.insert(name, function);
} }
@ -898,6 +1043,7 @@ pub mod error {
//! The [Error] type represents any error thrown by the [Environment](super::Environment) //! The [Error] type represents any error thrown by the [Environment](super::Environment)
use super::temp_type_impl::ConValue; use super::temp_type_impl::ConValue;
use crate::ast::Loc;
pub type IResult<T> = Result<T, Error>; pub type IResult<T> = Result<T, Error>;
@ -921,6 +1067,12 @@ pub mod error {
TypeError, TypeError,
/// In clause of For loop didn't yield a Range /// In clause of For loop didn't yield a Range
NotIterable, NotIterable,
/// A value at this [location](struct@Loc) can't be indexed
NotIndexable(Loc),
/// An array index went out of bounds
OobIndex(usize, usize),
/// An expression at this [location](struct@Loc)ation is not assignable
NotAssignable(Loc),
/// A name was not defined in scope before being used /// A name was not defined in scope before being used
NotDefined(String), NotDefined(String),
/// A name was defined but not initialized /// A name was defined but not initialized
@ -943,6 +1095,15 @@ pub mod error {
Error::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f), Error::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
Error::TypeError => "Incompatible types".fmt(f), Error::TypeError => "Incompatible types".fmt(f),
Error::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f), Error::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
Error::NotIndexable(location) => {
write!(f, "{location} expression cannot be indexed")
}
Error::OobIndex(idx, len) => {
write!(f, "Index out of bounds: index was {idx}. but len is {len}")
}
Error::NotAssignable(location) => {
write!(f, "{location} expression is not assignable")
}
Error::NotDefined(value) => { Error::NotDefined(value) => {
write!(f, "{value} not bound. Did you mean `let {value};`?") write!(f, "{value} not bound. Did you mean `let {value};`?")
} }
@ -950,7 +1111,7 @@ pub mod error {
write!(f, "{value} bound, but not initialized") write!(f, "{value} bound, but not initialized")
} }
Error::NotCallable(value) => { Error::NotCallable(value) => {
write!(f, "{value} is not a function, and cannot be called") write!(f, "{value} is not callable.")
} }
Error::ArgNumber { want, got } => { Error::ArgNumber { want, got } => {
write!(f, "Expected {want} arguments, got {got}") write!(f, "Expected {want} arguments, got {got}")

View File

@ -49,12 +49,30 @@ mod macros {
//! env_eq!(env.x, 10); // like assert_eq! for Environments //! env_eq!(env.x, 10); // like assert_eq! for Environments
//! ``` //! ```
#![allow(unused_macros)] #![allow(unused_macros)]
use crate::interpreter::IResult;
use super::*; use super::*;
pub fn test_inside_block(block: &Block, env: &mut Environment) -> IResult<()> {
let Block { stmts } = block;
for stmt in stmts {
stmt.interpret(env)?;
}
Ok(())
}
/// Stringifies, lexes, and parses everything you give to it /// Stringifies, lexes, and parses everything you give to it
/// ///
/// Returns a `Result<`[`Start`]`, ParseError>` /// Returns a `Result<`[`File`]`, ParseError>`
pub macro parse($($t:tt)*) { pub macro file($($t:tt)*) {
Parser::from(Lexer::new(stringify!( $($t)* ))).parse() Parser::new(Lexer::new(stringify!( $($t)* ))).file()
}
/// Stringifies, lexes, and parses everything you give to it
///
/// Returns a `Result<`[`Block`]`, ParseError>`
pub macro block($($t:tt)*) {
Parser::new(Lexer::new(stringify!({ $($t)* }))).block()
} }
/// Evaluates a block of code in the given environment /// Evaluates a block of code in the given environment
@ -68,9 +86,9 @@ mod macros {
/// ) /// )
/// ``` /// ```
pub macro eval($env: path, $($t:tt)*) {{ pub macro eval($env: path, $($t:tt)*) {{
parse!($($t)*) test_inside_block(&block!($($t)*)
.expect("code passed to eval! should parse correctly") .expect("code passed to eval! should parse correctly"),
.interpret(&mut $env) &mut $env)
}} }}
/// Evaluates a block of code in the given environment, expecting the interpreter to succeed /// Evaluates a block of code in the given environment, expecting the interpreter to succeed
@ -194,7 +212,7 @@ mod fn_declarations {
} }
mod operators { mod operators {
use crate::ast::preamble::expression::tuple; use crate::ast::Tuple;
use super::*; use super::*;
#[test] #[test]
@ -337,6 +355,7 @@ mod operators {
let is_20_ne_10 = 20 != 10; let is_20_ne_10 = 20 != 10;
let is_20_ge_10 = 20 >= 10; let is_20_ge_10 = 20 >= 10;
let is_20_gt_10 = 20 > 10; let is_20_gt_10 = 20 > 10;
dump();
); );
// Less than // Less than

View File

@ -10,8 +10,6 @@ pub mod lexer;
pub mod parser; pub mod parser;
pub mod pretty_printer;
pub mod resolver; pub mod resolver;
pub mod interpreter; pub mod interpreter;

File diff suppressed because it is too large Load Diff

View File

@ -1,460 +0,0 @@
//! A [Printer] pretty-prints a Conlang [syntax tree](crate::ast)
#![deprecated]
#![allow(deprecated)]
use super::ast::preamble::*;
use std::{
fmt::Display,
io::{stdout, Result as IOResult, StdoutLock, Write},
};
/// Prettily prints this node
pub trait PrettyPrintable {
/// Prettily prints this node
fn print(&self) {
let _ = self.visit(&mut Printer::default());
}
/// Prettily writes this node into the given [Writer](Write)
fn write(&self, into: impl Write) -> IOResult<()> {
self.visit(&mut Printer::from(into))
}
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()>;
}
/// Prints a Conlang [syntax tree](crate::ast) into a [Writer](Write)
#[derive(Debug)]
pub struct Printer<W: Write> {
level: u32,
writer: W,
}
impl<W: Write> Write for Printer<W> {
#[inline]
fn write(&mut self, buf: &[u8]) -> IOResult<usize> {
self.writer.write(buf)
}
#[inline]
fn flush(&mut self) -> IOResult<()> {
self.writer.flush()
}
}
impl<'t> Default for Printer<StdoutLock<'t>> {
fn default() -> Self {
Self { level: 0, writer: stdout().lock() }
}
}
impl<W: Write> From<W> for Printer<W> {
fn from(writer: W) -> Self {
Self { level: 0, writer }
}
}
impl<W: Write> Printer<W> {
fn pad(&mut self) -> IOResult<&mut Self> {
for _ in 0..self.level * 4 {
write!(self.writer, " ")?;
}
Ok(self)
}
fn newline(&mut self) -> IOResult<&mut Self> {
writeln!(self.writer)?;
self.pad()
}
fn put(&mut self, d: impl Display) -> IOResult<&mut Self> {
write!(self.writer, "{d}")?;
Ok(self)
}
fn space(&mut self) -> IOResult<&mut Self> {
write!(self.writer, " ").map(|_| self)
}
/// Increase the indentation level by 1
fn indent(&mut self) -> &mut Self {
self.level += 1;
self
}
fn dedent(&mut self) -> &mut Self {
self.level -= 1;
self
}
}
macro visit_operator($self:ident.$op:expr) {
$self.space()?.put($op)?.space().map(drop)
}
impl PrettyPrintable for Start {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Self(program) = self;
program.visit(p)
}
}
impl PrettyPrintable for Program {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Self(module) = self;
for decl in module {
decl.visit(p)?;
p.newline()?;
}
Ok(())
}
}
impl PrettyPrintable for Stmt {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
match self {
Stmt::Let(value) => value.visit(p),
Stmt::Fn(value) => value.visit(p),
Stmt::Expr(value) => {
value.visit(p)?;
p.put(';')?.newline().map(drop)
}
}
}
}
impl PrettyPrintable for Let {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Let { name: Name { symbol: name, mutable, ty }, init } = self;
p.put("let")?.space()?;
if *mutable {
p.put("mut")?.space()?;
}
name.visit(p)?;
if let Some(ty) = ty {
ty.visit(p.put(':')?.space()?)?
}
if let Some(init) = init {
init.visit(p.space()?.put('=')?.space()?)?;
}
p.put(';').map(drop)
}
}
impl PrettyPrintable for FnDecl {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let FnDecl { name, args, body } = self;
p.put("fn")?.space()?;
name.visit(p)?;
p.space()?.put('(')?;
for (idx, arg) in args.iter().enumerate() {
if idx > 0 {
p.put(',')?.space()?;
}
arg.visit(p)?;
}
p.put(')')?.space()?;
body.visit(p)
}
}
impl PrettyPrintable for Name {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
if self.mutable {
p.put("mut")?.space()?;
}
self.symbol.visit(p)?;
if let Some(ty) = &self.ty {
ty.visit(p.put(':')?.space()?)?;
}
Ok(())
}
}
impl PrettyPrintable for TypeExpr {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
match self {
TypeExpr::TupleType(_tt) => todo!(),
TypeExpr::TypePath(t) => t.visit(p),
TypeExpr::Empty(_) => p.put("()").map(drop),
TypeExpr::Never(_) => p.put('!').map(drop),
}
}
}
impl PrettyPrintable for Path {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Path { absolute, parts } = self;
if *absolute {
p.put("::")?;
}
for (idx, part) in parts.iter().enumerate() {
if idx != 0 {
p.put("::")?;
}
part.visit(p)?;
}
Ok(())
}
}
impl PrettyPrintable for PathPart {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
match self {
PathPart::PathSuper => p.put("super").map(drop),
PathPart::PathSelf => p.put("self").map(drop),
PathPart::PathIdent(id) => id.visit(p),
}
}
}
impl PrettyPrintable for Block {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Block { let_count: _, statements, expr } = self;
p.put('{')?.indent().newline()?;
for stmt in statements {
stmt.visit(p)?;
}
for expr in expr {
expr.visit(p)?;
}
p.dedent().newline()?.put('}').map(drop)
}
}
impl PrettyPrintable for Expr {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Expr(expr) = self;
expr.visit(p)
}
}
impl PrettyPrintable for Operation {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
match self {
Operation::Assign(value) => value.visit(p),
Operation::Binary(value) => value.visit(p),
Operation::Unary(value) => value.visit(p),
Operation::Call(value) => value.visit(p),
}
}
}
impl PrettyPrintable for Assign {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Assign { target, operator, init } = self;
target.visit(p)?;
operator.visit(p)?;
init.visit(p)
}
}
impl PrettyPrintable for operator::Assign {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
use operator::Assign;
visit_operator!(p.match self {
Assign::Assign => "=",
Assign::AddAssign => "+=",
Assign::SubAssign => "-=",
Assign::MulAssign => "*=",
Assign::DivAssign => "/=",
Assign::RemAssign => "%=",
Assign::BitAndAssign => "&=",
Assign::BitOrAssign => "|=",
Assign::BitXorAssign => "^=",
Assign::ShlAssign => "<<=",
Assign::ShrAssign => ">>=",
})
}
}
impl PrettyPrintable for Binary {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Binary { first, other } = self;
p.put('(')?;
first.visit(p)?;
for (op, other) in other {
op.visit(p)?;
other.visit(p)?
}
p.put(')').map(drop)
}
}
impl PrettyPrintable for operator::Binary {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
use operator::Binary;
visit_operator!(p.match self {
Binary::Mul => "*",
Binary::Div => "/",
Binary::Rem => "%",
Binary::Add => "+",
Binary::Sub => "-",
Binary::Lsh => "<<",
Binary::Rsh => ">>",
Binary::BitAnd => "&",
Binary::BitOr => "|",
Binary::BitXor => "^",
Binary::LogAnd => "&&",
Binary::LogOr => "||",
Binary::LogXor => "^^",
Binary::RangeExc => "..",
Binary::RangeInc => "..=",
Binary::Less => "<",
Binary::LessEq => "<=",
Binary::Equal => "==",
Binary::NotEq => "!=",
Binary::GreaterEq => ">=",
Binary::Greater => ">",
})
}
}
impl PrettyPrintable for Unary {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Unary { operators, operand } = self;
for op in operators {
op.visit(p)?;
}
operand.visit(p)
}
}
impl PrettyPrintable for operator::Unary {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
use operator::Unary;
p.put(match self {
Unary::RefRef => "&&",
Unary::Deref => "*",
Unary::Ref => "&",
Unary::Neg => "-",
Unary::Not => "!",
Unary::At => "@",
Unary::Hash => "#",
Unary::Tilde => "~",
})
.map(drop)
}
}
impl PrettyPrintable for Call {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
match self {
Call::FnCall(value) => value.visit(p),
Call::Primary(value) => value.visit(p),
}
}
}
impl PrettyPrintable for FnCall {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let FnCall { callee, args } = self;
callee.visit(p)?;
for arg_list in args {
p.put('(')?;
arg_list.visit(p)?;
p.put(')')?;
}
Ok(())
}
}
impl PrettyPrintable for Primary {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
match self {
Primary::Identifier(value) => value.visit(p),
Primary::Literal(value) => value.visit(p),
Primary::Block(value) => value.visit(p),
Primary::Group(value) => value.visit(p),
Primary::Branch(value) => value.visit(p),
}
}
}
impl PrettyPrintable for Group {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
p.put('(')?;
match self {
Group::Tuple(tuple) => tuple.visit(p.space()?)?,
Group::Single(expr) => expr.visit(p.space()?)?,
Group::Empty => (),
};
p.space()?.put(')').map(drop)
}
}
impl PrettyPrintable for Tuple {
/// Writes a *non-delimited* [Tuple] to the [Printer]
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Tuple { elements } = self;
for (idx, expr) in elements.iter().enumerate() {
if idx > 0 {
p.put(',')?.space()?;
}
expr.visit(p)?;
}
Ok(())
}
}
impl PrettyPrintable for Identifier {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Identifier { name, index: _ } = self; // TODO: Pretty-print variable number as well
p.put(name).map(drop)
}
}
impl PrettyPrintable for Literal {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
match self {
Literal::String(value) => write!(p, "\"{value}\""),
Literal::Char(value) => write!(p, "'{value}'"),
Literal::Bool(value) => write!(p, "{value}"),
Literal::Float(value) => value.visit(p),
Literal::Int(value) => write!(p, "{value}"),
}
}
}
impl PrettyPrintable for Float {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Float { sign, exponent, mantissa } = self;
p.put(sign)?.put(exponent)?.put(mantissa).map(drop)
}
}
impl PrettyPrintable for Flow {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
match self {
Flow::While(value) => value.visit(p),
Flow::If(value) => value.visit(p),
Flow::For(value) => value.visit(p),
Flow::Continue(value) => value.visit(p),
Flow::Return(value) => value.visit(p),
Flow::Break(value) => value.visit(p),
}
}
}
impl PrettyPrintable for While {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let While { cond, body, else_ } = self;
cond.visit(p.put("while")?.space()?)?;
body.visit(p.space()?)?;
match else_ {
Some(e) => e.visit(p),
None => Ok(()),
}
}
}
impl PrettyPrintable for If {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let If { cond, body, else_ } = self;
cond.visit(p.put("if")?.space()?)?;
body.visit(p.space()?)?;
match else_ {
Some(e) => e.visit(p),
None => Ok(()),
}
}
}
impl PrettyPrintable for For {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let For { var, iter, body, else_ } = self;
var.visit(p.put("for")?.space()?)?;
iter.visit(p.space()?.put("in")?.space()?)?;
body.visit(p.space()?)?;
match else_ {
Some(e) => e.visit(p),
None => Ok(()),
}
}
}
impl PrettyPrintable for Else {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Else { expr } = self;
expr.visit(p.space()?.put("else")?.space()?)
}
}
impl PrettyPrintable for Continue {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let control::Continue = self; // using pattern destructuring, rather than assigning to "Continue"
p.put("continue").map(drop)
}
}
impl PrettyPrintable for Break {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Break { expr } = self;
expr.visit(p.put("break")?.space()?)
}
}
impl PrettyPrintable for Return {
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
let Return { expr } = self;
expr.visit(p.put("return")?.space()?)
}
}

View File

@ -456,6 +456,7 @@ impl Resolver {
self.get_mut(name)?.assign(name, ty) self.get_mut(name)?.assign(name, ty)
} }
} }
#[allow(unused_macros)]
/// Manages a module scope /// Manages a module scope
/// ```rust,ignore /// ```rust,ignore
/// macro module(self, name: &str, inner: {...}) -> Result<_, Error> /// macro module(self, name: &str, inner: {...}) -> Result<_, Error>
@ -487,372 +488,375 @@ pub trait Resolve {
} }
} }
mod ast1 { mod ast1 {
#![allow(deprecated)] // #![allow(deprecated)]
use super::*; // use super::*;
use crate::ast::preamble::*; // use crate::ast::preamble::*;
impl Resolve for Start { // impl Resolve for Start {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> { // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Self(program) = self; // let Self(program) = self;
program.resolve(resolver) // program.resolve(resolver)
} // }
} // }
impl Resolve for Program { // impl Resolve for Program {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> { // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Self(module) = self; // let Self(module) = self;
for decl in module { // for decl in module {
decl.resolve(resolver)?; // decl.resolve(resolver)?;
} // }
// TODO: record the number of module-level assignments into the AST // // TODO: record the number of module-level assignments into the AST
Ok(Type::Empty) // Ok(Type::Empty)
} // }
} // }
impl Resolve for Stmt { // impl Resolve for Stmt {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> { // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
match self { // match self {
Stmt::Let(value) => value.resolve(resolver), // Stmt::Let(value) => value.resolve(resolver),
Stmt::Fn(value) => value.resolve(resolver), // Stmt::Fn(value) => value.resolve(resolver),
Stmt::Expr(value) => value.resolve(resolver), // Stmt::Expr(value) => value.resolve(resolver),
} // }
} // }
} // }
impl Resolve for Let { // impl Resolve for Let {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> { // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Let { name: Name { symbol: Identifier { name, index }, mutable, ty: _ }, init } = // let Let { name: Name { symbol: Identifier { name, index }, mutable, ty: _ }, init } =
self; // self;
debugln!("ty> let {name} ..."); // debugln!("ty> let {name} ...");
if let Some(init) = init { // if let Some(init) = init {
let ty = init.resolve(resolver)?; // let ty = init.resolve(resolver)?;
*index = Some(resolver.insert_scope(name, *mutable)?); // *index = Some(resolver.insert_scope(name, *mutable)?);
resolver.get_mut(name)?.assign(name, &ty)?; // resolver.get_mut(name)?.assign(name, &ty)?;
} else { // } else {
resolver.insert_scope(name, *mutable)?; // resolver.insert_scope(name, *mutable)?;
} // }
Ok(Type::Empty) // Ok(Type::Empty)
} // }
} // }
impl Resolve for FnDecl { // impl Resolve for FnDecl {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> { // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let FnDecl { name: Name { symbol: Identifier { name, index }, .. }, args, body } = self; // let FnDecl { name: Name { symbol: Identifier { name, index }, .. }, args, body } =
debugln!("ty> fn {name} ..."); // self; debugln!("ty> fn {name} ...");
// register the name at module scope // // register the name at module scope
*index = Some(resolver.insert_module(name, false)?); // *index = Some(resolver.insert_module(name, false)?);
// create a new lexical scope // // create a new lexical scope
let scopes = std::mem::take(&mut resolver.scopes); // let scopes = std::mem::take(&mut resolver.scopes);
// type-check the function body // // type-check the function body
let out = { // let out = {
let mut resolver = resolver.frame(); // let mut resolver = resolver.frame();
let mut evaluated_args = vec![]; // let mut evaluated_args = vec![];
for arg in args { // for arg in args {
evaluated_args.push(arg.resolve(&mut resolver)?) // evaluated_args.push(arg.resolve(&mut resolver)?)
} // }
let fn_decl = Type::Fn { args: evaluated_args.clone(), ret: Box::new(Type::Empty) }; // let fn_decl = Type::Fn { args: evaluated_args.clone(), ret: Box::new(Type::Empty)
resolver.get_mut(name)?.assign(name, &fn_decl)?; // }; resolver.get_mut(name)?.assign(name, &fn_decl)?;
module!(resolver, name, { body.resolve(&mut resolver) }) // module!(resolver, name, { body.resolve(&mut resolver) })
}; // };
let _ = std::mem::replace(&mut resolver.scopes, scopes); // let _ = std::mem::replace(&mut resolver.scopes, scopes);
out // out
} // }
} // }
impl Resolve for Name { // impl Resolve for Name {
fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> { // fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
Ok(Type::Empty) // Ok(Type::Empty)
} // }
} // }
impl Resolve for Block { // impl Resolve for Block {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> { // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Block { let_count: _, statements, expr } = self; // let Block { let_count: _, statements, expr } = self;
let mut resolver = resolver.frame(); // let mut resolver = resolver.frame();
for stmt in statements { // for stmt in statements {
stmt.resolve(&mut resolver)?; // stmt.resolve(&mut resolver)?;
} // }
expr.resolve(&mut resolver) // expr.resolve(&mut resolver)
} // }
} // }
impl Resolve for Expr { // impl Resolve for Expr {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> { // fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Expr(expr) = self; // let Expr(expr) = self;
expr.resolve(resolver) // expr.resolve(resolver)
} // }
// }
// impl Resolve for Operation {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// match self {
// Operation::Assign(value) => value.resolve(resolver),
// Operation::Binary(value) => value.resolve(resolver),
// Operation::Unary(value) => value.resolve(resolver),
// Operation::Call(value) => value.resolve(resolver),
// }
// }
// }
// impl Resolve for Assign {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Assign { target, operator, init } = self;
// // Evaluate the initializer expression
// let ty = init.resolve(resolver)?;
// // Resolve the variable
// match (operator, resolver.get_mut(&target.name)?) {
// (
// operator::Assign::Assign,
// Variable { status: Status::Initialized(_), mutable: false, index },
// ) => Err(Error::ImmutableAssign(target.name.clone(), *index)),
// // TODO: make typing more expressive for modifying assignment
// (_, variable) => variable
// .modify_assign(&target.name, &ty)
// .map(|_| Type::Empty),
// }
// }
// }
// impl Resolve for Binary {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Binary { first, other } = self;
// let mut first = first.resolve(resolver)?;
// for (op, other) in other {
// let other = other.resolve(resolver)?;
// first = resolver.resolve_binary_operator(first, other, op)?;
// }
// Ok(first)
// }
// }
// impl Resolve for Unary {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Unary { operators, operand } = self;
// let mut operand = operand.resolve(resolver)?;
// for op in operators {
// operand = resolver.resolve_unary_operator(operand, op)?;
// }
// Ok(operand)
// }
// }
// /// Resolve [operator]s
// impl Resolver {
// fn resolve_binary_operator(
// &mut self,
// first: Type,
// other: Type,
// op: &operator::Binary,
// ) -> TyResult<Type> {
// // TODO: check type compatibility for binary ops
// // TODO: desugar binary ops into function calls, when member functions are a thing
// eprintln!("Resolve binary operators {first} {op:?} {other}");
// if first != other {
// Err(Error::TypeMismatch { want: first, got: other })
// } else {
// Ok(first)
// }
// }
// fn resolve_unary_operator(
// &mut self,
// operand: Type,
// op: &operator::Unary,
// ) -> TyResult<Type> {
// // TODO: Allow more expressive unary operator type conversions
// todo!("Resolve unary operators {op:?} {operand}")
// }
// }
// impl Resolve for Call {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// match self {
// Call::FnCall(value) => value.resolve(resolver),
// Call::Primary(value) => value.resolve(resolver),
// }
// }
// }
// impl Resolve for FnCall {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let FnCall { callee, args } = self;
// let mut callee = callee.resolve(resolver)?;
// for argset in args {
// // arguments should always be a tuple here
// let arguments = argset.resolve(resolver)?;
// let Type::Tuple(arguments) = arguments else {
// Err(Error::TypeMismatch {
// want: Type::Tuple(vec![Type::ManyInferred]),
// got: arguments,
// })?
// };
// // Verify that the callee is a function, and the arguments match.
// // We need the arguments
// let Type::Fn { args, ret } = callee else {
// return Err(Error::TypeMismatch {
// want: Type::Fn { args: arguments, ret: Type::Inferred.into() },
// got: callee,
// })?;
// };
// for (want, got) in args.iter().zip(&arguments) {
// // TODO: verify generics
// if let Type::Generic(_) = want {
// continue;
// }
// if want != got {
// return Err(Error::TypeMismatch {
// want: Type::Fn { args: arguments, ret: Type::Inferred.into() },
// got: Type::Fn { args, ret },
// })?;
// }
// }
// callee = *ret;
// }
// Ok(callee)
// }
// }
// impl Resolve for Primary {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// match self {
// Primary::Identifier(value) => value.resolve(resolver),
// Primary::Literal(value) => value.resolve(resolver),
// Primary::Block(value) => value.resolve(resolver),
// Primary::Group(value) => value.resolve(resolver),
// Primary::Branch(value) => value.resolve(resolver),
// }
// }
// }
// impl Resolve for Group {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// match self {
// Group::Tuple(tuple) => tuple.resolve(resolver),
// Group::Single(expr) => expr.resolve(resolver),
// Group::Empty => Ok(Type::Empty),
// }
// }
// }
// impl Resolve for Tuple {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Tuple { elements } = self;
// let mut types = vec![];
// for expr in elements.iter_mut() {
// types.push(expr.resolve(resolver)?);
// }
// Ok(Type::Tuple(types))
// }
// }
// impl Resolve for Identifier {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Identifier { name, index: id_index } = self;
// let Variable { index, status, .. } = resolver.get(name)?;
// *id_index = Some(*index);
// let ty = match status {
// Status::Initialized(t) => t,
// _ => Err(Error::Uninitialized(name.to_owned(), *index))?,
// };
// debugln!("ty> Resolved {} #{index}: {ty}", name);
// Ok(ty.to_owned())
// }
// }
// impl Resolve for Literal {
// fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
// Ok(match self {
// Literal::String(_) => Type::String,
// Literal::Char(_) => Type::Char,
// Literal::Bool(_) => Type::Bool,
// Literal::Float(_) => Type::Float,
// Literal::Int(_) => Type::Int,
// })
// }
// }
// impl Resolve for Flow {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// // TODO: Finish this
// match self {
// Flow::While(value) => value.resolve(resolver),
// Flow::If(value) => value.resolve(resolver),
// Flow::For(value) => value.resolve(resolver),
// Flow::Continue(value) => value.resolve(resolver),
// Flow::Return(value) => value.resolve(resolver),
// Flow::Break(value) => value.resolve(resolver),
// }
// }
// }
// impl Resolve for While {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// // TODO: Finish this
// // Visit else first, save that to a break-pattern stack in the Resolver,
// // and check it inside Break::resolve()
// let While { cond, body, else_ } = self;
// cond.resolve(resolver)?; // must be Type::Bool
// body.resolve(resolver)?; // discard
// else_.resolve(resolver) // compare with returns inside body
// }
// }
// impl Resolve for If {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let If { cond, body, else_ } = self;
// let cond = cond.resolve(resolver)?;
// if Type::Bool != cond {
// return Err(Error::TypeMismatch { want: Type::Bool, got: cond });
// }
// let body_ty = body.resolve(resolver)?;
// let else_ty = else_.resolve(resolver)?;
// if body_ty == else_ty {
// Ok(body_ty)
// } else {
// Err(Error::TypeMismatch { want: body_ty, got: else_ty })
// }
// }
// }
// impl Resolve for For {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let For { var: Identifier { name, index }, iter, body, else_ } = self;
// debugln!("> for {name} in ...");
// // Visit the iter expression and get its type
// let range = iter.resolve(resolver)?;
// let ty = match range {
// Type::Range(t) => t,
// got => Err(Error::TypeMismatch { want: Type::Range(Type::Inferred.into()), got
// })?, };
// let body_ty = {
// let mut resolver = resolver.frame();
// // bind the variable in the loop scope
// *index = Some(resolver.insert_scope(name, false)?);
// resolver.get_mut(name)?.assign(name, &ty)?;
// body.resolve(&mut resolver)
// }?;
// // visit the else block
// let else_ty = else_.resolve(resolver)?;
// if body_ty != else_ty {
// Err(Error::TypeMismatch { want: body_ty, got: else_ty })
// } else {
// Ok(body_ty)
// }
// }
// }
// impl Resolve for Else {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Else { expr } = self;
// expr.resolve(resolver)
// }
// }
// impl Resolve for Continue {
// fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
// // TODO: Finish control flow
// Ok(Type::Never)
// }
// }
// impl Resolve for Break {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// // TODO: Finish control flow
// let Break { expr } = self;
// expr.resolve(resolver)
// }
// }
// impl Resolve for Return {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// // TODO: Finish control flow
// let Return { expr } = self;
// expr.resolve(resolver)
// }
// }
} }
impl Resolve for Operation { mod ast {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> { #![allow(unused_imports)]
match self { use crate::ast::*;
Operation::Assign(value) => value.resolve(resolver),
Operation::Binary(value) => value.resolve(resolver),
Operation::Unary(value) => value.resolve(resolver),
Operation::Call(value) => value.resolve(resolver),
} }
}
}
impl Resolve for Assign {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Assign { target, operator, init } = self;
// Evaluate the initializer expression
let ty = init.resolve(resolver)?;
// Resolve the variable
match (operator, resolver.get_mut(&target.name)?) {
(
operator::Assign::Assign,
Variable { status: Status::Initialized(_), mutable: false, index },
) => Err(Error::ImmutableAssign(target.name.clone(), *index)),
// TODO: make typing more expressive for modifying assignment
(_, variable) => variable
.modify_assign(&target.name, &ty)
.map(|_| Type::Empty),
}
}
}
impl Resolve for Binary {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Binary { first, other } = self;
let mut first = first.resolve(resolver)?;
for (op, other) in other {
let other = other.resolve(resolver)?;
first = resolver.resolve_binary_operator(first, other, op)?;
}
Ok(first)
}
}
impl Resolve for Unary {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Unary { operators, operand } = self;
let mut operand = operand.resolve(resolver)?;
for op in operators {
operand = resolver.resolve_unary_operator(operand, op)?;
}
Ok(operand)
}
}
/// Resolve [operator]s
impl Resolver {
fn resolve_binary_operator(
&mut self,
first: Type,
other: Type,
op: &operator::Binary,
) -> TyResult<Type> {
// TODO: check type compatibility for binary ops
// TODO: desugar binary ops into function calls, when member functions are a thing
eprintln!("Resolve binary operators {first} {op:?} {other}");
if first != other {
Err(Error::TypeMismatch { want: first, got: other })
} else {
Ok(first)
}
}
fn resolve_unary_operator(
&mut self,
operand: Type,
op: &operator::Unary,
) -> TyResult<Type> {
// TODO: Allow more expressive unary operator type conversions
todo!("Resolve unary operators {op:?} {operand}")
}
}
impl Resolve for Call {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
match self {
Call::FnCall(value) => value.resolve(resolver),
Call::Primary(value) => value.resolve(resolver),
}
}
}
impl Resolve for FnCall {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let FnCall { callee, args } = self;
let mut callee = callee.resolve(resolver)?;
for argset in args {
// arguments should always be a tuple here
let arguments = argset.resolve(resolver)?;
let Type::Tuple(arguments) = arguments else {
Err(Error::TypeMismatch {
want: Type::Tuple(vec![Type::ManyInferred]),
got: arguments,
})?
};
// Verify that the callee is a function, and the arguments match.
// We need the arguments
let Type::Fn { args, ret } = callee else {
return Err(Error::TypeMismatch {
want: Type::Fn { args: arguments, ret: Type::Inferred.into() },
got: callee,
})?;
};
for (want, got) in args.iter().zip(&arguments) {
// TODO: verify generics
if let Type::Generic(_) = want {
continue;
}
if want != got {
return Err(Error::TypeMismatch {
want: Type::Fn { args: arguments, ret: Type::Inferred.into() },
got: Type::Fn { args, ret },
})?;
}
}
callee = *ret;
}
Ok(callee)
}
}
impl Resolve for Primary {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
match self {
Primary::Identifier(value) => value.resolve(resolver),
Primary::Literal(value) => value.resolve(resolver),
Primary::Block(value) => value.resolve(resolver),
Primary::Group(value) => value.resolve(resolver),
Primary::Branch(value) => value.resolve(resolver),
}
}
}
impl Resolve for Group {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
match self {
Group::Tuple(tuple) => tuple.resolve(resolver),
Group::Single(expr) => expr.resolve(resolver),
Group::Empty => Ok(Type::Empty),
}
}
}
impl Resolve for Tuple {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Tuple { elements } = self;
let mut types = vec![];
for expr in elements.iter_mut() {
types.push(expr.resolve(resolver)?);
}
Ok(Type::Tuple(types))
}
}
impl Resolve for Identifier {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Identifier { name, index: id_index } = self;
let Variable { index, status, .. } = resolver.get(name)?;
*id_index = Some(*index);
let ty = match status {
Status::Initialized(t) => t,
_ => Err(Error::Uninitialized(name.to_owned(), *index))?,
};
debugln!("ty> Resolved {} #{index}: {ty}", name);
Ok(ty.to_owned())
}
}
impl Resolve for Literal {
fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
Ok(match self {
Literal::String(_) => Type::String,
Literal::Char(_) => Type::Char,
Literal::Bool(_) => Type::Bool,
Literal::Float(_) => Type::Float,
Literal::Int(_) => Type::Int,
})
}
}
impl Resolve for Flow {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// TODO: Finish this
match self {
Flow::While(value) => value.resolve(resolver),
Flow::If(value) => value.resolve(resolver),
Flow::For(value) => value.resolve(resolver),
Flow::Continue(value) => value.resolve(resolver),
Flow::Return(value) => value.resolve(resolver),
Flow::Break(value) => value.resolve(resolver),
}
}
}
impl Resolve for While {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// TODO: Finish this
// Visit else first, save that to a break-pattern stack in the Resolver,
// and check it inside Break::resolve()
let While { cond, body, else_ } = self;
cond.resolve(resolver)?; // must be Type::Bool
body.resolve(resolver)?; // discard
else_.resolve(resolver) // compare with returns inside body
}
}
impl Resolve for If {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let If { cond, body, else_ } = self;
let cond = cond.resolve(resolver)?;
if Type::Bool != cond {
return Err(Error::TypeMismatch { want: Type::Bool, got: cond });
}
let body_ty = body.resolve(resolver)?;
let else_ty = else_.resolve(resolver)?;
if body_ty == else_ty {
Ok(body_ty)
} else {
Err(Error::TypeMismatch { want: body_ty, got: else_ty })
}
}
}
impl Resolve for For {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let For { var: Identifier { name, index }, iter, body, else_ } = self;
debugln!("> for {name} in ...");
// Visit the iter expression and get its type
let range = iter.resolve(resolver)?;
let ty = match range {
Type::Range(t) => t,
got => Err(Error::TypeMismatch { want: Type::Range(Type::Inferred.into()), got })?,
};
let body_ty = {
let mut resolver = resolver.frame();
// bind the variable in the loop scope
*index = Some(resolver.insert_scope(name, false)?);
resolver.get_mut(name)?.assign(name, &ty)?;
body.resolve(&mut resolver)
}?;
// visit the else block
let else_ty = else_.resolve(resolver)?;
if body_ty != else_ty {
Err(Error::TypeMismatch { want: body_ty, got: else_ty })
} else {
Ok(body_ty)
}
}
}
impl Resolve for Else {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Else { expr } = self;
expr.resolve(resolver)
}
}
impl Resolve for Continue {
fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
// TODO: Finish control flow
Ok(Type::Never)
}
}
impl Resolve for Break {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// TODO: Finish control flow
let Break { expr } = self;
expr.resolve(resolver)
}
}
impl Resolve for Return {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// TODO: Finish control flow
let Return { expr } = self;
expr.resolve(resolver)
}
}
}
mod ast2 {}
// heakc yea man, generics // heakc yea man, generics
impl<T: Resolve> Resolve for Option<T> { impl<T: Resolve> Resolve for Option<T> {

View File

@ -78,6 +78,7 @@ pub enum Type {
pub enum Keyword { pub enum Keyword {
Break, Break,
Cl, Cl,
Const,
Continue, Continue,
Else, Else,
Enum, Enum,
@ -85,13 +86,16 @@ pub enum Keyword {
For, For,
Fn, Fn,
If, If,
Impl,
In, In,
Let, Let,
Mod, Mod,
Mut, Mut,
Pub,
Return, Return,
SelfKw, SelfKw,
SelfTy, SelfTy,
Static,
Struct, Struct,
Super, Super,
True, True,
@ -172,6 +176,7 @@ impl Display for Keyword {
match self { match self {
Self::Break => "break".fmt(f), Self::Break => "break".fmt(f),
Self::Cl => "cl".fmt(f), Self::Cl => "cl".fmt(f),
Self::Const => "const".fmt(f),
Self::Continue => "continue".fmt(f), Self::Continue => "continue".fmt(f),
Self::Else => "else".fmt(f), Self::Else => "else".fmt(f),
Self::Enum => "enum".fmt(f), Self::Enum => "enum".fmt(f),
@ -179,13 +184,16 @@ impl Display for Keyword {
Self::For => "for".fmt(f), Self::For => "for".fmt(f),
Self::Fn => "fn".fmt(f), Self::Fn => "fn".fmt(f),
Self::If => "if".fmt(f), Self::If => "if".fmt(f),
Self::Impl => "impl".fmt(f),
Self::In => "in".fmt(f), Self::In => "in".fmt(f),
Self::Let => "let".fmt(f), Self::Let => "let".fmt(f),
Self::Mod => "mod".fmt(f), Self::Mod => "mod".fmt(f),
Self::Mut => "mut".fmt(f), Self::Mut => "mut".fmt(f),
Self::Pub => "pub".fmt(f),
Self::Return => "return".fmt(f), Self::Return => "return".fmt(f),
Self::SelfKw => "self".fmt(f), Self::SelfKw => "self".fmt(f),
Self::SelfTy => "Self".fmt(f), Self::SelfTy => "Self".fmt(f),
Self::Static => "static".fmt(f),
Self::Struct => "struct".fmt(f), Self::Struct => "struct".fmt(f),
Self::Super => "super".fmt(f), Self::Super => "super".fmt(f),
Self::True => "true".fmt(f), Self::True => "true".fmt(f),
@ -200,6 +208,7 @@ impl FromStr for Keyword {
Ok(match s { Ok(match s {
"break" => Self::Break, "break" => Self::Break,
"cl" => Self::Cl, "cl" => Self::Cl,
"const" => Self::Const,
"continue" => Self::Continue, "continue" => Self::Continue,
"else" => Self::Else, "else" => Self::Else,
"enum" => Self::Enum, "enum" => Self::Enum,
@ -207,13 +216,16 @@ impl FromStr for Keyword {
"for" => Self::For, "for" => Self::For,
"fn" => Self::Fn, "fn" => Self::Fn,
"if" => Self::If, "if" => Self::If,
"impl" => Self::Impl,
"in" => Self::In, "in" => Self::In,
"let" => Self::Let, "let" => Self::Let,
"mod" => Self::Mod, "mod" => Self::Mod,
"mut" => Self::Mut, "mut" => Self::Mut,
"pub" => Self::Pub,
"return" => Self::Return, "return" => Self::Return,
"self" => Self::SelfKw, "self" => Self::SelfKw,
"Self" => Self::SelfTy, "Self" => Self::SelfTy,
"static" => Self::Static,
"struct" => Self::Struct, "struct" => Self::Struct,
"super" => Self::Super, "super" => Self::Super,
"true" => Self::True, "true" => Self::True,