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:
parent
5e2f365f45
commit
c4a32895df
@ -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"
|
||||
|
@ -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>) {
|
||||
|
178
grammar.ebnf
178
grammar.ebnf
@ -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
744
libconlang/src/ast/ast_impl.rs
Normal file
744
libconlang/src/ast/ast_impl.rs
Normal 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() }
|
||||
}
|
||||
}
|
||||
}
|
@ -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}")
|
||||
|
@ -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
|
||||
|
@ -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
@ -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()?)
|
||||
}
|
||||
}
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user