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]
repository = "https://git.soft.fish/j/Conlang"
version = "0.0.2"
version = "0.0.3"
authors = ["John Breaux <j@soft.fish>"]
edition = "2021"
license = "MIT"

View File

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

View File

@ -1,84 +1,130 @@
(* Conlang Expression Grammar *)
Start = Program ;
Program = Stmt* EOI ;
(* TODO:
- Replace Program with Module
Module = Decl* EOI ;
- Move Fn and Let into "Decl":
Decl = Fn | Let ;
- allow Decl | ExprStmt in Stmt:
Stmt = Decl | Expr ';' ;
*)
(* literal *)
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
Bool = "true" | "false" ;
Identifier = IDENTIFIER ;
Start = File ;
Mutability = "mut"? ;
Visibility = "pub"? ;
File = Item* EOI ;
Item = Visibility (
Const | Static | Module
| Function | Struct | Enum
| Impl
) ;
(* 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 *)
Stmt = Fn | Let | Expr ';' ;
Let = "let" Name ('=' Expr)? ';' ;
Fn = "fn" Identifier '(' Params? ')' Block ;
(* TODO: Type system *)
Params = (Name ',')* Name? ;
Name = "mut"? Identifier (':' Type )? ;
Stmt = ';' | (Let | Item | Expr ';'?) ;
Let = "let" Mutability Identifier (':' Ty)? ('=' Expr)? ;
(* TODO: Closure syntax *)
Closure = "cl" '(' Param* ')' Block ;
(* # Type Expressions *)
(* types *)
TypeExpr = Never | Empty | TypeTuple | PathExpr ;
(* type *)
Ty = Never | Empty | TyTuple | Path | TyRef | TyFn ;
Never = '!' ;
Empty = '(' ')' ;
TypeTuple = '(' (TypeExpr ',')* TypeExpr? ')' ;
PathExpr = '::'? PathPart ;
PathPart = "super" | Identifier ;
TyTuple = '(' (Ty ',')* Ty? ')' ;
TyRef = ('&' | '&&')* Path ;
TyFn = "fn" TyTuple (-> Ty)? ;
(* # Expressions *)
(* expression *)
(* path *)
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 ;
Block = '{' Stmt* Expr? '}' ;
Primary = Identifier | Literal
| Block | Group | Branch ;
(* expression::call *)
Call = FnCall | Primary ;
FnCall = Primary ('(' Tuple? ')')? ;
Assign = Path (AssignOp Assign ) | Compare ;
(* expression::tuple *)
Group = '(' Tuple? ')' ;
Tuple = Expr (',' Expr)* ;
Binary = Compare | Range | Logic | Bitwise | Shift | Factor | Term ;
Compare = Range (CompareOp Range )* ;
Range = Logic (RangeOp Logic )* ;
Logic = Bitwise (LogicOp Bitwise)* ;
Bitwise = Shift (BitwiseOp Shift )* ;
Shift = Factor (ShiftOp Factor )* ;
Factor = Term (FactorOp Term )* ;
Term = Unary (FactorOp Unary )* ;
(* expression::math *)
Assign = Identifier (AssignOp Assign) | Compare ;
Compare = Range (CompareOp Range )* ;
Range = Logic (RangeOp Logic )* ;
Logic = Bitwise (LogicOp Bitwise)* ;
Bitwise = Shift (BitwiseOp Shift )* ;
Shift = Term (ShiftOp Term )* ;
Term = Factor (TermOp Factor )* ;
Factor = Unary (FactorOp Unary )* ;
Unary = (UnaryOp)* Call ;
Unary = (UnaryOp)* Member ;
(* expression::math::operator *)
AssignOp = '=' | "+=" | "-=" | "*=" | "/=" |
"&=" | "|=" | "^=" |"<<=" |">>=" ;
CompareOp = '<' | "<=" | "==" | "!=" | ">=" | '>' ;
RangeOp = ".." | "..=" ;
LogicOp = "&&" | "||" | "^^" ;
Member = Call ('.' Call)* ;
BitwiseOp = '&' | '|' | '^' ;
ShiftOp = "<<" | ">>";
TermOp = '+' | '-' ;
FactorOp = '*' | '/' | '%' ;
UnaryOp = '*' | '&' | '-' | '!' ;
Call = Index ('(' Tuple? ')')* ;
(* expression::control *)
Branch = While | If | For | Break | Return | Continue ;
If = "if" Expr Block (Else)? ;
While = "while" Expr Block (Else)? ;
For = "for" Identifier "in" Expr Block (Else)? ;
Else = "else" Expr ;
Index = Primary ('[' Indices ']')* ;
Indices = (Expr ',')* Expr? ;
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 ;
Break = "break" Expr ;
Return = "return" Expr ;
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
use crate::ast::preamble::*;
use env::Environment;
use error::{Error, IResult};
use interpret::Interpret;
use temp_type_impl::ConValue;
/// Callable types can be called from within a Conlang program
@ -44,6 +44,8 @@ pub mod temp_type_impl {
Char(char),
/// A string
String(String),
/// An Array
Array(Vec<ConValue>),
/// A tuple
Tuple(Vec<ConValue>),
/// An exclusive range
@ -75,6 +77,17 @@ pub mod temp_type_impl {
};
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! {
lt: false, <;
lt_eq: true, <=;
@ -259,6 +272,16 @@ pub mod temp_type_impl {
ConValue::Bool(v) => v.fmt(f),
ConValue::Char(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::RangeInc(a, b) => write!(f, "{a}..={b}"),
ConValue::Tuple(tuple) => {
@ -282,352 +305,472 @@ pub mod temp_type_impl {
}
}
/// A work-in-progress tree walk interpreter for Conlang
pub trait Interpret {
/// Interprets this thing in the given [`Environment`].
///
/// Everything returns a value!™
fn interpret(&self, env: &mut Environment) -> IResult<ConValue>;
}
pub mod interpret {
use super::*;
use crate::ast::*;
/// A work-in-progress tree walk interpreter for Conlang
pub trait Interpret {
/// Interprets this thing in the given [`Environment`].
///
/// Everything returns a value!™
fn interpret(&self, env: &mut Environment) -> IResult<ConValue>;
}
impl Interpret for Start {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
self.0.interpret(env)
}
}
impl Interpret for Program {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let mut out = ConValue::Empty;
for stmt in &self.0 {
out = stmt.interpret(env)?;
}
Ok(out)
}
}
impl Interpret for Stmt {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self {
Stmt::Let(l) => l.interpret(env),
Stmt::Fn(f) => f.interpret(env),
Stmt::Expr(e) => e.interpret(env),
}
}
}
impl Interpret for Let {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Let { name: Name { symbol: Identifier { name, .. }, .. }, init, .. } = self;
if let Some(init) = init {
let init = init.interpret(env)?;
env.insert(name, Some(init));
} else {
env.insert(name, None);
}
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 {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
self.0.interpret(env)
}
}
impl Interpret for Operation {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self {
Operation::Assign(op) => op.interpret(env),
Operation::Binary(op) => op.interpret(env),
Operation::Unary(op) => op.interpret(env),
Operation::Call(op) => op.interpret(env),
}
}
}
impl Interpret for Assign {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
use operator::Assign;
let math::Assign { target: Identifier { name, .. }, operator, init } = self;
let init = init.interpret(env)?;
let target = env.get_mut(name)?;
if let Assign::Assign = operator {
use std::mem::discriminant as variant;
// runtime typecheck
match target {
Some(value) if variant(value) == variant(&init) => {
*value = init;
}
value @ None => *value = Some(init),
_ => Err(Error::TypeError)?,
impl Interpret for File {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
for item in &self.items {
item.interpret(env)?;
}
return Ok(ConValue::Empty);
Ok(ConValue::Empty)
}
let Some(target) = target else {
return Err(Error::NotInitialized(name.into()));
};
match operator {
Assign::AddAssign => target.add_assign(init)?,
Assign::SubAssign => target.sub_assign(init)?,
Assign::MulAssign => target.mul_assign(init)?,
Assign::DivAssign => target.div_assign(init)?,
Assign::RemAssign => target.rem_assign(init)?,
Assign::BitAndAssign => target.bitand_assign(init)?,
Assign::BitOrAssign => target.bitor_assign(init)?,
Assign::BitXorAssign => target.bitxor_assign(init)?,
Assign::ShlAssign => target.shl_assign(init)?,
Assign::ShrAssign => target.shr_assign(init)?,
_ => (),
}
Ok(ConValue::Empty)
}
}
impl Interpret for Binary {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Binary { first, other } = self;
let mut first = first.interpret(env)?;
for (op, other) in other {
first = match op {
operator::Binary::LogAnd => {
if first.truthy()? {
other.interpret(env)
} else {
return Ok(first); // Short circuiting
impl Interpret for Item {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match &self.kind {
ItemKind::Const(item) => item.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),
}
}
}
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 {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { extents: _, kind, semi } = self;
let out = match kind {
StmtKind::Empty => ConValue::Empty,
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 {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Let { mutable: _, name: Identifier(name), init } = self;
if let Some(init) = init {
let init = init.interpret(env)?;
env.insert(name, Some(init));
} else {
env.insert(name, None);
}
Ok(ConValue::Empty)
}
}
impl Interpret for Expr {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { extents: _, kind } = self;
match kind {
ExprKind::Assign(v) => v.interpret(env),
ExprKind::Binary(v) => v.interpret(env),
ExprKind::Unary(v) => v.interpret(env),
ExprKind::Member(v) => v.interpret(env),
ExprKind::Call(v) => v.interpret(env),
ExprKind::Index(v) => v.interpret(env),
ExprKind::Path(v) => v.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 {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Assign { head, op, tail } = self;
// Resolve the head pattern
let head = match &head.kind {
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,
}
}
operator::Binary::LogOr => {
if !first.truthy()? {
other.interpret(env)
} else {
return Ok(first); // Short circuiting
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 AssignKind::Plain = op {
use std::mem::discriminant as variant;
// runtime typecheck
match target {
Some(value) if variant(value) == variant(&init) => {
*value = init;
}
value @ None => *value = Some(init),
_ => Err(Error::TypeError)?,
}
return Ok(ConValue::Empty);
}
let Some(target) = target else {
return Err(Error::NotInitialized(head.into()));
};
match op {
AssignKind::Add => target.add_assign(init)?,
AssignKind::Sub => target.sub_assign(init)?,
AssignKind::Mul => target.mul_assign(init)?,
AssignKind::Div => target.div_assign(init)?,
AssignKind::Rem => target.rem_assign(init)?,
AssignKind::And => target.bitand_assign(init)?,
AssignKind::Or => target.bitor_assign(init)?,
AssignKind::Xor => target.bitxor_assign(init)?,
AssignKind::Shl => target.shl_assign(init)?,
AssignKind::Shr => target.shr_assign(init)?,
_ => (),
}
Ok(ConValue::Empty)
}
}
impl Interpret for Binary {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Binary { head, tail } = self;
let mut head = head.interpret(env)?;
for (op, tail) in tail {
head = match op {
BinaryKind::LogAnd => {
if head.truthy()? {
tail.interpret(env)
} else {
return Ok(head); // Short circuiting
}
}
BinaryKind::LogOr => {
if !head.truthy()? {
tail.interpret(env)
} else {
return Ok(head); // Short circuiting
}
}
BinaryKind::LogXor => {
// TODO: It should be possible to assemble better error information from
// this
let (lhs, rhs) = (head.truthy()?, tail.interpret(env)?.truthy()?);
Ok(ConValue::Bool(lhs ^ rhs))
}
// TODO: For all overloadable operators, transmute into function call
BinaryKind::Mul => head * tail.interpret(env)?,
BinaryKind::Div => head / tail.interpret(env)?,
BinaryKind::Rem => head % tail.interpret(env)?,
BinaryKind::Add => head + tail.interpret(env)?,
BinaryKind::Sub => head - tail.interpret(env)?,
BinaryKind::Shl => head << tail.interpret(env)?,
BinaryKind::Shr => head >> tail.interpret(env)?,
BinaryKind::BitAnd => head & tail.interpret(env)?,
BinaryKind::BitOr => head | tail.interpret(env)?,
BinaryKind::BitXor => head ^ tail.interpret(env)?,
BinaryKind::RangeExc => head.range_exc(tail.interpret(env)?),
BinaryKind::RangeInc => head.range_inc(tail.interpret(env)?),
BinaryKind::Lt => head.lt(&tail.interpret(env)?),
BinaryKind::LtEq => head.lt_eq(&tail.interpret(env)?),
BinaryKind::Equal => head.eq(&tail.interpret(env)?),
BinaryKind::NotEq => head.neq(&tail.interpret(env)?),
BinaryKind::GtEq => head.gt_eq(&tail.interpret(env)?),
BinaryKind::Gt => head.gt(&tail.interpret(env)?),
BinaryKind::Dot => todo!("search within a type's namespace!"),
}?;
}
Ok(head)
}
}
impl Interpret for Unary {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Unary { tail, ops } = self;
let mut operand = tail.interpret(env)?;
for op in ops.iter().rev() {
operand = match op {
UnaryKind::Deref => todo!("Deref operator"),
UnaryKind::Neg => (-operand)?,
UnaryKind::Not => (!operand)?,
UnaryKind::At => unimplemented!("At operator"),
UnaryKind::Hash => {
println!("{operand}");
operand
}
UnaryKind::Tilde => unimplemented!("Tilde operator"),
};
}
Ok(operand)
}
}
impl Interpret for Member {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
todo!("Interpret member accesses in {env}")
}
}
impl Interpret for Call {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { callee, args } = self;
// evaluate the callee
let mut callee = callee.interpret(env)?;
for args in args {
let ConValue::Tuple(args) = args.interpret(env)? else {
Err(Error::TypeError)?
};
callee = callee.call(env, &args)?;
}
Ok(callee)
}
}
impl Interpret for Index {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { head, indices } = self;
let mut head = head.interpret(env)?;
for indices in indices {
let Indices { exprs } = indices;
for index in exprs {
head = head.index(&index.interpret(env)?)?;
}
}
Ok(head)
}
}
impl Interpret for Path {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
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 {
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
Ok(match self {
Literal::String(value) => ConValue::from(value.as_str()),
Literal::Char(value) => ConValue::Char(*value),
Literal::Bool(value) => ConValue::Bool(*value),
// Literal::Float(value) => todo!("Float values in interpreter: {value:?}"),
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 {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { stmts } = self;
let mut env = env.frame("block");
let mut out = ConValue::Empty;
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)?;
ConValue::Empty
}
_ => {
stmt.interpret(&mut env)?;
continue;
}
}
operator::Binary::LogXor => {
// TODO: It should be possible to assemble better error information from this
let (lhs, rhs) = (first.truthy()?, other.interpret(env)?.truthy()?);
Ok(ConValue::Bool(lhs ^ rhs))
}
Ok(out)
}
}
impl Interpret for Group {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { expr } = self;
expr.interpret(env)
}
}
impl Interpret for Tuple {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { exprs } = self;
Ok(ConValue::Tuple(exprs.iter().try_fold(
vec![],
|mut out, element| {
out.push(element.interpret(env)?);
Ok(out)
},
)?))
}
}
impl Interpret for While {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { cond, pass, fail } = self;
while cond.interpret(env)?.truthy()? {
match pass.interpret(env) {
Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue,
e => e?,
};
}
fail.interpret(env)
}
}
impl Interpret for If {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { cond, pass, fail } = self;
if cond.interpret(env)?.truthy()? {
pass.interpret(env)
} else {
fail.interpret(env)
}
}
}
impl Interpret for For {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
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::RangeInc(a, b) => a..=b,
_ => Err(Error::TypeError)?,
};
{
let mut env = env.frame("loop variable");
for loop_var in bounds {
env.insert(name, Some(loop_var.into()));
match pass.interpret(&mut env) {
Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue,
result => result?,
};
}
// TODO: For all overloadable operators, transmute into function call
operator::Binary::Mul => first * other.interpret(env)?,
operator::Binary::Div => first / other.interpret(env)?,
operator::Binary::Rem => first % other.interpret(env)?,
operator::Binary::Add => first + other.interpret(env)?,
operator::Binary::Sub => first - other.interpret(env)?,
operator::Binary::Lsh => first << other.interpret(env)?,
operator::Binary::Rsh => first >> other.interpret(env)?,
operator::Binary::BitAnd => first & other.interpret(env)?,
operator::Binary::BitOr => first | other.interpret(env)?,
operator::Binary::BitXor => first ^ other.interpret(env)?,
operator::Binary::RangeExc => first.range_exc(other.interpret(env)?),
operator::Binary::RangeInc => first.range_inc(other.interpret(env)?),
operator::Binary::Less => first.lt(&other.interpret(env)?),
operator::Binary::LessEq => first.lt_eq(&other.interpret(env)?),
operator::Binary::Equal => first.eq(&other.interpret(env)?),
operator::Binary::NotEq => first.neq(&other.interpret(env)?),
operator::Binary::GreaterEq => first.gt_eq(&other.interpret(env)?),
operator::Binary::Greater => first.gt(&other.interpret(env)?),
}?;
}
Ok(first)
}
}
impl Interpret for Unary {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Unary { operand, operators } = self;
let mut operand = operand.interpret(env)?;
for op in operators.iter().rev() {
operand = match op {
operator::Unary::RefRef => todo!(),
operator::Unary::Ref => todo!(),
operator::Unary::Deref => todo!(),
operator::Unary::Neg => (-operand)?,
operator::Unary::Not => (!operand)?,
operator::Unary::At => todo!(),
operator::Unary::Hash => {
println!("{operand}");
operand
}
operator::Unary::Tilde => todo!(),
};
}
Ok(operand)
}
}
impl Interpret for Call {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self {
Call::FnCall(fncall) => fncall.interpret(env),
Call::Primary(primary) => primary.interpret(env),
}
fail.interpret(env)
}
}
}
impl Interpret for FnCall {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
// evaluate the callee
let mut callee = self.callee.interpret(env)?;
for args in &self.args {
let ConValue::Tuple(args) = args.interpret(env)? else {
Err(Error::TypeError)?
};
callee = callee.call(env, &args)?;
}
Ok(callee)
}
}
impl Interpret for Primary {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self {
Primary::Identifier(prim) => prim.interpret(env),
Primary::Literal(prim) => prim.interpret(env),
Primary::Block(prim) => prim.interpret(env),
Primary::Group(prim) => prim.interpret(env),
Primary::Branch(prim) => prim.interpret(env),
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),
}
}
}
}
impl Interpret for Identifier {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
env.get(&self.name).cloned()
}
}
impl Interpret for Literal {
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
Ok(match self {
Literal::String(value) => ConValue::from(value.as_str()),
Literal::Char(value) => ConValue::Char(*value),
Literal::Bool(value) => ConValue::Bool(*value),
Literal::Float(value) => todo!("Float values in interpreter: {value:?}"),
Literal::Int(value) => ConValue::Int(*value as _),
})
}
}
impl Interpret for Block {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let mut env = env.frame("block");
// TODO: this could TOTALLY be done with a binary operator.
for stmt in &self.statements {
stmt.interpret(&mut env)?;
}
if let Some(expr) = self.expr.as_ref() {
expr.interpret(&mut env)
} else {
Ok(ConValue::Empty)
impl Interpret for Continue {
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
Err(Error::Continue)
}
}
}
impl Interpret for Group {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
match self {
Group::Tuple(tuple) => tuple.interpret(env),
Group::Single(value) => value.interpret(env),
Group::Empty => Ok(ConValue::Empty),
impl Interpret for Return {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { body } = self;
Err(Error::Return(
body.as_ref()
.map(|body| body.interpret(env))
.unwrap_or(Ok(ConValue::Empty))?,
))
}
}
}
impl Interpret for Tuple {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
Ok(ConValue::Tuple(self.elements.iter().try_fold(
vec![],
|mut out, element| {
out.push(element.interpret(env)?);
Ok(out)
},
)?))
}
}
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 Break {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { body } = self;
Err(Error::Return(
body.as_ref()
.map(|body| body.interpret(env))
.unwrap_or(Ok(ConValue::Empty))?,
))
}
}
}
impl Interpret for While {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
while self.cond.interpret(env)?.truthy()? {
match self.body.interpret(env) {
Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue,
e => e?,
};
}
if let Some(other) = &self.else_ {
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 {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
if self.cond.interpret(env)?.truthy()? {
self.body.interpret(env)
} else if let Some(other) = &self.else_ {
other.interpret(env)
} else {
Ok(ConValue::Empty)
}
}
}
impl Interpret for For {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let bounds = match self.iter.interpret(env)? {
ConValue::RangeExc(a, b) => a..=b,
ConValue::RangeInc(a, b) => a..=b,
_ => Err(Error::TypeError)?,
};
let mut env = env.frame("loop variable");
for loop_var in bounds {
env.insert(&self.var.name, Some(loop_var.into()));
match self.body.interpret(&mut env) {
Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue,
result => result?,
};
}
if let Some(other) = &self.else_ {
other.interpret(&mut env)
} else {
Ok(ConValue::Empty)
}
}
}
impl Interpret for Continue {
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
Err(Error::Continue)
}
}
impl Interpret for Return {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
Err(Error::Return(self.expr.interpret(env)?))
}
}
impl Interpret for Break {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
Err(Error::Break(self.expr.interpret(env)?))
}
}
pub mod function {
//! Represents a block of code which lives inside the Interpreter
use super::{Callable, ConValue, Environment, Error, FnDecl, IResult, Identifier, Interpret};
use crate::ast::preamble::Name;
use super::{Callable, ConValue, Environment, Error, IResult, Interpret};
use crate::ast::{Function as FnDecl, Identifier, Param};
/// Represents a block of code which persists inside the Interpreter
#[derive(Clone, Debug)]
pub struct Function {
@ -645,22 +788,26 @@ pub mod function {
impl Callable for Function {
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> {
let FnDecl { name: Identifier(name), args: declargs, body, rety: _ } = &*self.decl;
// Check arg mapping
if args.len() != self.decl.args.len() {
return Err(Error::ArgNumber { want: self.decl.args.len(), got: args.len() });
if args.len() != declargs.len() {
return Err(Error::ArgNumber { want: declargs.len(), got: args.len() });
}
// TODO: Isolate cross-function scopes!
// let mut env = self.env.clone();
let Some(body) = body else {
return Err(Error::NotDefined(name.into()));
};
// TODO: completely refactor data storage
let mut frame = env.frame("fn args");
for (Name { symbol: Identifier { name, .. }, .. }, value) in
self.decl.args.iter().zip(args)
for (Param { mutability: _, name: Identifier(name), ty: _ }, value) in
declargs.iter().zip(args)
{
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::Break(value)) => Err(Error::BadBreak(value)),
result => result,
@ -734,14 +881,14 @@ pub mod builtin {
pub mod env {
//! Lexical and non-lexical scoping for variables
use super::{
builtin::DEFAULT_BUILTINS,
error::{Error, IResult},
function::Function,
temp_type_impl::ConValue,
Callable, FnDecl, Interpret,
Callable, Interpret,
};
use crate::ast::{Function as FnDecl, Identifier};
use std::{
collections::HashMap,
fmt::Display,
@ -838,10 +985,8 @@ pub mod env {
}
/// A convenience function for registering a [FnDecl] as a [Function]
pub fn insert_fn(&mut self, decl: &FnDecl) {
let (name, function) = (
decl.name.symbol.name.clone(),
Some(Function::new(decl).into()),
);
let FnDecl { name: Identifier(name), .. } = decl;
let (name, function) = (name.clone(), Some(Function::new(decl).into()));
if let Some((frame, _)) = self.frames.last_mut() {
frame.insert(name, function);
}
@ -898,6 +1043,7 @@ pub mod error {
//! The [Error] type represents any error thrown by the [Environment](super::Environment)
use super::temp_type_impl::ConValue;
use crate::ast::Loc;
pub type IResult<T> = Result<T, Error>;
@ -921,6 +1067,12 @@ pub mod error {
TypeError,
/// In clause of For loop didn't yield a Range
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
NotDefined(String),
/// 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::TypeError => "Incompatible types".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) => {
write!(f, "{value} not bound. Did you mean `let {value};`?")
}
@ -950,7 +1111,7 @@ pub mod error {
write!(f, "{value} bound, but not initialized")
}
Error::NotCallable(value) => {
write!(f, "{value} is not a function, and cannot be called")
write!(f, "{value} is not callable.")
}
Error::ArgNumber { want, 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
//! ```
#![allow(unused_macros)]
use crate::interpreter::IResult;
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
///
/// Returns a `Result<`[`Start`]`, ParseError>`
pub macro parse($($t:tt)*) {
Parser::from(Lexer::new(stringify!( $($t)* ))).parse()
/// Returns a `Result<`[`File`]`, ParseError>`
pub macro file($($t:tt)*) {
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
@ -68,9 +86,9 @@ mod macros {
/// )
/// ```
pub macro eval($env: path, $($t:tt)*) {{
parse!($($t)*)
.expect("code passed to eval! should parse correctly")
.interpret(&mut $env)
test_inside_block(&block!($($t)*)
.expect("code passed to eval! should parse correctly"),
&mut $env)
}}
/// Evaluates a block of code in the given environment, expecting the interpreter to succeed
@ -194,7 +212,7 @@ mod fn_declarations {
}
mod operators {
use crate::ast::preamble::expression::tuple;
use crate::ast::Tuple;
use super::*;
#[test]
@ -337,6 +355,7 @@ mod operators {
let is_20_ne_10 = 20 != 10;
let is_20_ge_10 = 20 >= 10;
let is_20_gt_10 = 20 > 10;
dump();
);
// Less than

View File

@ -10,8 +10,6 @@ pub mod lexer;
pub mod parser;
pub mod pretty_printer;
pub mod resolver;
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)
}
}
#[allow(unused_macros)]
/// Manages a module scope
/// ```rust,ignore
/// macro module(self, name: &str, inner: {...}) -> Result<_, Error>
@ -487,372 +488,375 @@ pub trait Resolve {
}
}
mod ast1 {
#![allow(deprecated)]
use super::*;
use crate::ast::preamble::*;
impl Resolve for Start {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Self(program) = self;
program.resolve(resolver)
}
}
impl Resolve for Program {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Self(module) = self;
for decl in module {
decl.resolve(resolver)?;
}
// TODO: record the number of module-level assignments into the AST
Ok(Type::Empty)
}
}
impl Resolve for Stmt {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
match self {
Stmt::Let(value) => value.resolve(resolver),
Stmt::Fn(value) => value.resolve(resolver),
Stmt::Expr(value) => value.resolve(resolver),
}
}
}
impl Resolve for Let {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Let { name: Name { symbol: Identifier { name, index }, mutable, ty: _ }, init } =
self;
debugln!("ty> let {name} ...");
if let Some(init) = init {
let ty = init.resolve(resolver)?;
*index = Some(resolver.insert_scope(name, *mutable)?);
resolver.get_mut(name)?.assign(name, &ty)?;
} else {
resolver.insert_scope(name, *mutable)?;
}
Ok(Type::Empty)
}
}
impl Resolve for FnDecl {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let FnDecl { name: Name { symbol: Identifier { name, index }, .. }, args, body } = self;
debugln!("ty> fn {name} ...");
// register the name at module scope
*index = Some(resolver.insert_module(name, false)?);
// create a new lexical scope
let scopes = std::mem::take(&mut resolver.scopes);
// type-check the function body
let out = {
let mut resolver = resolver.frame();
let mut evaluated_args = vec![];
for arg in args {
evaluated_args.push(arg.resolve(&mut resolver)?)
}
let fn_decl = Type::Fn { args: evaluated_args.clone(), ret: Box::new(Type::Empty) };
resolver.get_mut(name)?.assign(name, &fn_decl)?;
module!(resolver, name, { body.resolve(&mut resolver) })
};
let _ = std::mem::replace(&mut resolver.scopes, scopes);
out
}
}
impl Resolve for Name {
fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
Ok(Type::Empty)
}
}
impl Resolve for Block {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Block { let_count: _, statements, expr } = self;
let mut resolver = resolver.frame();
for stmt in statements {
stmt.resolve(&mut resolver)?;
}
expr.resolve(&mut resolver)
}
}
impl Resolve for Expr {
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
let Expr(expr) = self;
expr.resolve(resolver)
}
}
// #![allow(deprecated)]
// use super::*;
// use crate::ast::preamble::*;
// impl Resolve for Start {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Self(program) = self;
// program.resolve(resolver)
// }
// }
// impl Resolve for Program {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Self(module) = self;
// for decl in module {
// decl.resolve(resolver)?;
// }
// // TODO: record the number of module-level assignments into the AST
// Ok(Type::Empty)
// }
// }
// impl Resolve for Stmt {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// match self {
// Stmt::Let(value) => value.resolve(resolver),
// Stmt::Fn(value) => value.resolve(resolver),
// Stmt::Expr(value) => value.resolve(resolver),
// }
// }
// }
// impl Resolve for Let {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Let { name: Name { symbol: Identifier { name, index }, mutable, ty: _ }, init } =
// self;
// debugln!("ty> let {name} ...");
// if let Some(init) = init {
// let ty = init.resolve(resolver)?;
// *index = Some(resolver.insert_scope(name, *mutable)?);
// resolver.get_mut(name)?.assign(name, &ty)?;
// } else {
// resolver.insert_scope(name, *mutable)?;
// }
// Ok(Type::Empty)
// }
// }
// impl Resolve for FnDecl {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let FnDecl { name: Name { symbol: Identifier { name, index }, .. }, args, body } =
// self; debugln!("ty> fn {name} ...");
// // register the name at module scope
// *index = Some(resolver.insert_module(name, false)?);
// // create a new lexical scope
// let scopes = std::mem::take(&mut resolver.scopes);
// // type-check the function body
// let out = {
// let mut resolver = resolver.frame();
// let mut evaluated_args = vec![];
// for arg in args {
// evaluated_args.push(arg.resolve(&mut resolver)?)
// }
// let fn_decl = Type::Fn { args: evaluated_args.clone(), ret: Box::new(Type::Empty)
// }; resolver.get_mut(name)?.assign(name, &fn_decl)?;
// module!(resolver, name, { body.resolve(&mut resolver) })
// };
// let _ = std::mem::replace(&mut resolver.scopes, scopes);
// out
// }
// }
// impl Resolve for Name {
// fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
// Ok(Type::Empty)
// }
// }
// impl Resolve for Block {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Block { let_count: _, statements, expr } = self;
// let mut resolver = resolver.frame();
// for stmt in statements {
// stmt.resolve(&mut resolver)?;
// }
// expr.resolve(&mut resolver)
// }
// }
// impl Resolve for Expr {
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
// let Expr(expr) = self;
// 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 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;
// 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),
}
}
}
// 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 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 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 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 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 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 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 {}
mod ast {
#![allow(unused_imports)]
use crate::ast::*;
}
// heakc yea man, generics
impl<T: Resolve> Resolve for Option<T> {

View File

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