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]
|
[workspace.package]
|
||||||
repository = "https://git.soft.fish/j/Conlang"
|
repository = "https://git.soft.fish/j/Conlang"
|
||||||
version = "0.0.2"
|
version = "0.0.3"
|
||||||
authors = ["John Breaux <j@soft.fish>"]
|
authors = ["John Breaux <j@soft.fish>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
//! Utilities for cl-frontend
|
//! Utilities for cl-frontend
|
||||||
|
//!
|
||||||
|
//! # TODO
|
||||||
|
//! - [ ] Readline-like line editing
|
||||||
|
//! - [ ] Raw mode?
|
||||||
|
|
||||||
pub mod args {
|
pub mod args {
|
||||||
use crate::cli::Mode;
|
use crate::cli::Mode;
|
||||||
@ -14,7 +18,7 @@ pub mod args {
|
|||||||
pub repl: bool, // defaults true if stdin is terminal
|
pub repl: bool, // defaults true if stdin is terminal
|
||||||
pub mode: Mode, // defaults Interpret
|
pub mode: Mode, // defaults Interpret
|
||||||
}
|
}
|
||||||
const HELP: &str = "[( --repl | --no-repl )] [( -f | --file ) <filename>]";
|
const HELP: &str = "[( --repl | --no-repl )] [--mode (tokens | pretty | type | run)] [( -f | --file ) <filename>]";
|
||||||
|
|
||||||
impl Args {
|
impl Args {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@ -65,109 +69,132 @@ pub mod args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod program {
|
pub mod program {
|
||||||
use std::io::{Result as IOResult, Write};
|
use std::{fmt::Display, io::Write};
|
||||||
|
|
||||||
use conlang::{
|
use conlang::{
|
||||||
ast::preamble::{expression::Expr, *},
|
ast::{self, ast_impl::format::Pretty},
|
||||||
interpreter::{env::Environment, error::IResult},
|
interpreter::{
|
||||||
|
env::Environment, error::IResult, interpret::Interpret, temp_type_impl::ConValue,
|
||||||
|
},
|
||||||
|
// pretty_printer::{PrettyPrintable, Printer},
|
||||||
lexer::Lexer,
|
lexer::Lexer,
|
||||||
parser::{error::PResult, Parser},
|
parser::{error::PResult, Parser},
|
||||||
pretty_printer::{PrettyPrintable, Printer},
|
resolver::{error::TyResult, Resolver},
|
||||||
resolver::{error::TyResult, Resolve, Resolver},
|
|
||||||
token::Token,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Tokenized {
|
pub struct Parsable;
|
||||||
tokens: Vec<Token>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Parsed {
|
pub enum Parsed {
|
||||||
Program(Start),
|
File(ast::File),
|
||||||
Expr(Expr),
|
Stmt(ast::Stmt),
|
||||||
|
Expr(ast::Expr),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Tokenized> for Parsed {
|
pub struct Program<'t, Variant> {
|
||||||
type Error = conlang::parser::error::Error;
|
text: &'t str,
|
||||||
fn try_from(value: Tokenized) -> Result<Self, Self::Error> {
|
|
||||||
let mut parser = Parser::new(value.tokens);
|
|
||||||
let ast = parser.parse()?;
|
|
||||||
//if let Ok(ast) = ast {
|
|
||||||
//return
|
|
||||||
Ok(Self::Program(ast))
|
|
||||||
//}
|
|
||||||
|
|
||||||
//Ok(Self::Expr(parser.reset().parse_expr()?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Program<Variant> {
|
|
||||||
data: Variant,
|
data: Variant,
|
||||||
}
|
}
|
||||||
|
impl<'t, V> Program<'t, V> {
|
||||||
impl Program<Tokenized> {
|
pub fn lex(&self) -> Lexer {
|
||||||
pub fn new(input: &str) -> Result<Self, Vec<conlang::lexer::error::Error>> {
|
Lexer::new(self.text)
|
||||||
let mut tokens = vec![];
|
|
||||||
let mut errors = vec![];
|
|
||||||
for token in Lexer::new(input) {
|
|
||||||
match token {
|
|
||||||
Ok(token) => tokens.push(token),
|
|
||||||
Err(error) => errors.push(error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if errors.is_empty() {
|
|
||||||
Ok(Self { data: Tokenized { tokens } })
|
|
||||||
} else {
|
|
||||||
Err(errors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn tokens(&self) -> &[Token] {
|
|
||||||
&self.data.tokens
|
|
||||||
}
|
|
||||||
pub fn parse(self) -> PResult<Program<Parsed>> {
|
|
||||||
Ok(Program { data: Parsed::try_from(self.data)? })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Program<Parsed> {
|
impl<'t> Program<'t, Parsable> {
|
||||||
pub fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<()> {
|
pub fn new(text: &'t str) -> Self {
|
||||||
match &mut self.data {
|
Self { text, data: Parsable }
|
||||||
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 parse(self) -> PResult<Program<'t, Parsed>> {
|
||||||
pub fn run(&self, env: &mut Environment) -> IResult<()> {
|
self.parse_file().or_else(|_| self.parse_stmt())
|
||||||
println!(
|
}
|
||||||
"{}",
|
pub fn parse_expr(&self) -> PResult<Program<'t, Parsed>> {
|
||||||
match &self.data {
|
Ok(Program { data: Parsed::Expr(Parser::new(self.lex()).expr()?), text: self.text })
|
||||||
Parsed::Program(start) => env.eval(start)?,
|
}
|
||||||
Parsed::Expr(expr) => env.eval(expr)?,
|
pub fn parse_stmt(&self) -> PResult<Program<'t, Parsed>> {
|
||||||
}
|
Ok(Program { data: Parsed::Stmt(Parser::new(self.lex()).stmt()?), text: self.text })
|
||||||
);
|
}
|
||||||
Ok(())
|
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> {
|
impl<'t> Program<'t, Parsed> {
|
||||||
fn visit<W: Write>(&self, p: &mut Printer<W>) -> IOResult<()> {
|
pub fn debug(&self) {
|
||||||
match &self.data {
|
match &self.data {
|
||||||
Parsed::Program(value) => value.visit(p),
|
Parsed::File(v) => eprintln!("{v:?}"),
|
||||||
Parsed::Expr(value) => value.visit(p),
|
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 {
|
pub mod cli {
|
||||||
use conlang::{
|
use conlang::{interpreter::env::Environment, resolver::Resolver, token::Token};
|
||||||
interpreter::env::Environment, pretty_printer::PrettyPrintable, resolver::Resolver,
|
|
||||||
token::Token,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
args::Args,
|
args::Args,
|
||||||
program::{Parsed, Program, Tokenized},
|
program::{Parsable, Parsed, Program},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
@ -220,35 +247,30 @@ pub mod cli {
|
|||||||
}
|
}
|
||||||
fn no_repl(mode: Mode, path: Option<&Path>, code: &str) {
|
fn no_repl(mode: Mode, path: Option<&Path>, code: &str) {
|
||||||
let program = Program::new(code);
|
let program = Program::new(code);
|
||||||
match (mode, program) {
|
match mode {
|
||||||
(Mode::Tokenize, Ok(program)) => {
|
Mode::Tokenize => {
|
||||||
for token in program.tokens() {
|
for token in program.lex() {
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
print!("{}:", path.display());
|
print!("{}:", path.display());
|
||||||
}
|
}
|
||||||
print_token(token)
|
match token {
|
||||||
}
|
Ok(token) => print_token(&token),
|
||||||
}
|
Err(e) => println!("{e}"),
|
||||||
(Mode::Beautify, Ok(program)) => Self::beautify(program),
|
|
||||||
(Mode::Resolve, Ok(program)) => Self::resolve(program, Default::default()),
|
|
||||||
(Mode::Interpret, Ok(program)) => Self::interpret(program, Environment::new()),
|
|
||||||
(_, Err(errors)) => {
|
|
||||||
for error in errors {
|
|
||||||
if let Some(path) = path {
|
|
||||||
eprint!("{}:", path.display());
|
|
||||||
}
|
}
|
||||||
eprintln!("{error}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Mode::Beautify => Self::beautify(program),
|
||||||
|
Mode::Resolve => Self::resolve(program, Default::default()),
|
||||||
|
Mode::Interpret => Self::interpret(program, Environment::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn beautify(program: Program<Tokenized>) {
|
fn beautify(program: Program<Parsable>) {
|
||||||
match program.parse() {
|
match program.parse() {
|
||||||
Ok(program) => program.print(),
|
Ok(program) => program.print(),
|
||||||
Err(e) => eprintln!("{e}"),
|
Err(e) => eprintln!("{e}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn resolve(program: Program<Tokenized>, mut resolver: Resolver) {
|
fn resolve(program: Program<Parsable>, mut resolver: Resolver) {
|
||||||
let mut program = match program.parse() {
|
let mut program = match program.parse() {
|
||||||
Ok(program) => program,
|
Ok(program) => program,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -260,7 +282,7 @@ pub mod cli {
|
|||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn interpret(program: Program<Tokenized>, mut interpreter: Environment) {
|
fn interpret(program: Program<Parsable>, mut interpreter: Environment) {
|
||||||
let program = match program.parse() {
|
let program = match program.parse() {
|
||||||
Ok(program) => program,
|
Ok(program) => program,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -301,10 +323,10 @@ pub mod cli {
|
|||||||
type Err = Infallible;
|
type Err = Infallible;
|
||||||
fn from_str(s: &str) -> Result<Self, Infallible> {
|
fn from_str(s: &str) -> Result<Self, Infallible> {
|
||||||
Ok(match s {
|
Ok(match s {
|
||||||
"i" | "interpret" => Mode::Interpret,
|
"i" | "interpret" | "run" => Mode::Interpret,
|
||||||
"b" | "beautify" | "p" | "pretty" => Mode::Beautify,
|
"b" | "beautify" | "p" | "pretty" => Mode::Beautify,
|
||||||
"r" | "resolve" | "typecheck" => Mode::Resolve,
|
"r" | "resolve" | "typecheck" | "type" => Mode::Resolve,
|
||||||
"t" | "tokenize" => Mode::Tokenize,
|
"t" | "tokenize" | "tokens" => Mode::Tokenize,
|
||||||
_ => Mode::Interpret,
|
_ => Mode::Interpret,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -386,12 +408,12 @@ pub mod cli {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Lex the buffer, or reset and output the error
|
// Lex the buffer, or reset and output the error
|
||||||
let code = match Program::new(&buf) {
|
let code = Program::new(&buf);
|
||||||
Ok(code) => code,
|
match code.lex().into_iter().find(|l| l.is_err()) {
|
||||||
Err(e) => {
|
None => (),
|
||||||
for error in e {
|
Some(Ok(_)) => unreachable!(),
|
||||||
eprintln!("{error}");
|
Some(Err(error)) => {
|
||||||
}
|
eprintln!("{error}");
|
||||||
self.reprompt(&mut buf);
|
self.reprompt(&mut buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -451,9 +473,12 @@ pub mod cli {
|
|||||||
Mode::Interpret => self.interpret(code),
|
Mode::Interpret => self.interpret(code),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn tokenize(&mut self, code: &Program<Tokenized>) {
|
fn tokenize(&mut self, code: &Program<Parsable>) {
|
||||||
for token in code.tokens() {
|
for token in code.lex() {
|
||||||
print_token(token);
|
match token {
|
||||||
|
Ok(token) => print_token(&token),
|
||||||
|
Err(e) => println!("{e}"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn interpret(&mut self, code: &Program<Parsed>) {
|
fn interpret(&mut self, code: &Program<Parsed>) {
|
||||||
|
178
grammar.ebnf
178
grammar.ebnf
@ -1,84 +1,130 @@
|
|||||||
(* Conlang Expression Grammar *)
|
(* Conlang Expression Grammar *)
|
||||||
Start = Program ;
|
Start = File ;
|
||||||
Program = Stmt* EOI ;
|
|
||||||
(* TODO:
|
Mutability = "mut"? ;
|
||||||
- Replace Program with Module
|
Visibility = "pub"? ;
|
||||||
Module = Decl* EOI ;
|
|
||||||
- Move Fn and Let into "Decl":
|
|
||||||
Decl = Fn | Let ;
|
File = Item* EOI ;
|
||||||
- allow Decl | ExprStmt in Stmt:
|
|
||||||
Stmt = Decl | Expr ';' ;
|
|
||||||
*)
|
Item = Visibility (
|
||||||
(* literal *)
|
Const | Static | Module
|
||||||
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
|
| Function | Struct | Enum
|
||||||
Bool = "true" | "false" ;
|
| Impl
|
||||||
Identifier = IDENTIFIER ;
|
) ;
|
||||||
|
|
||||||
|
|
||||||
|
(* item *)
|
||||||
|
Const = "const" Identifier ':' Type = Expr ';' ;
|
||||||
|
|
||||||
|
Static = "static" Mutability Identifier ':' Type = Expr ';' ;
|
||||||
|
|
||||||
|
Module = "mod" Identifier '{' (Item)* '}' ;
|
||||||
|
|
||||||
|
Function = "fn" Identifier '(' (Param ',')* Param? ')' ( '->' Type) Block ;
|
||||||
|
Param = Identifier ':' Type ;
|
||||||
|
|
||||||
|
Struct = "struct" Identifier (TupleStruct | StructStruct)?;
|
||||||
|
StructStruct= '{' (Identifier ':' Type),* '}' ;
|
||||||
|
TupleStruct = TyTuple ;
|
||||||
|
|
||||||
|
Enum = "enum" Identifier (TupleEnum | StructEnum)? ;
|
||||||
|
TupleEnum = TyTuple;
|
||||||
|
StructEnum = '{' (Identifier ':' Type)* '}' ;
|
||||||
|
|
||||||
|
|
||||||
(* # Statements *)
|
|
||||||
(* statement *)
|
(* statement *)
|
||||||
Stmt = Fn | Let | Expr ';' ;
|
Stmt = ';' | (Let | Item | Expr ';'?) ;
|
||||||
Let = "let" Name ('=' Expr)? ';' ;
|
Let = "let" Mutability Identifier (':' Ty)? ('=' Expr)? ;
|
||||||
Fn = "fn" Identifier '(' Params? ')' Block ;
|
(* TODO: Closure syntax *)
|
||||||
(* TODO: Type system *)
|
Closure = "cl" '(' Param* ')' Block ;
|
||||||
Params = (Name ',')* Name? ;
|
|
||||||
Name = "mut"? Identifier (':' Type )? ;
|
|
||||||
|
|
||||||
(* # Type Expressions *)
|
|
||||||
(* types *)
|
(* type *)
|
||||||
TypeExpr = Never | Empty | TypeTuple | PathExpr ;
|
Ty = Never | Empty | TyTuple | Path | TyRef | TyFn ;
|
||||||
Never = '!' ;
|
Never = '!' ;
|
||||||
Empty = '(' ')' ;
|
Empty = '(' ')' ;
|
||||||
TypeTuple = '(' (TypeExpr ',')* TypeExpr? ')' ;
|
TyTuple = '(' (Ty ',')* Ty? ')' ;
|
||||||
|
TyRef = ('&' | '&&')* Path ;
|
||||||
PathExpr = '::'? PathPart ;
|
TyFn = "fn" TyTuple (-> Ty)? ;
|
||||||
PathPart = "super" | Identifier ;
|
|
||||||
|
|
||||||
|
|
||||||
(* # Expressions *)
|
(* path *)
|
||||||
(* expression *)
|
Path = '::'? PathPart ('::' PathPart)* ;
|
||||||
|
PathPart = "super" | "self" | Identifier ;
|
||||||
|
Identifier = IDENTIFIER ;
|
||||||
|
|
||||||
|
|
||||||
|
(* literal *)
|
||||||
|
Bool = "true" | "false" ;
|
||||||
|
|
||||||
|
|
||||||
|
(* expr *)
|
||||||
|
ExprKind = Assign | Compare | Range | Logic | Bitwise | Shift
|
||||||
|
| Factor | Term | Unary | Member | Call | Index
|
||||||
|
| Path | Literal | Array | ArrayRep | AddrOf
|
||||||
|
| Block | Group
|
||||||
|
| While | If | For | Break | Return | Continue ;
|
||||||
|
|
||||||
Expr = Assign ;
|
Expr = Assign ;
|
||||||
Block = '{' Stmt* Expr? '}' ;
|
|
||||||
Primary = Identifier | Literal
|
|
||||||
| Block | Group | Branch ;
|
|
||||||
|
|
||||||
(* expression::call *)
|
Assign = Path (AssignOp Assign ) | Compare ;
|
||||||
Call = FnCall | Primary ;
|
|
||||||
FnCall = Primary ('(' Tuple? ')')? ;
|
|
||||||
|
|
||||||
(* expression::tuple *)
|
Binary = Compare | Range | Logic | Bitwise | Shift | Factor | Term ;
|
||||||
Group = '(' Tuple? ')' ;
|
Compare = Range (CompareOp Range )* ;
|
||||||
Tuple = Expr (',' Expr)* ;
|
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 *)
|
Unary = (UnaryOp)* Member ;
|
||||||
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 ;
|
|
||||||
|
|
||||||
(* expression::math::operator *)
|
Member = Call ('.' Call)* ;
|
||||||
AssignOp = '=' | "+=" | "-=" | "*=" | "/=" |
|
|
||||||
"&=" | "|=" | "^=" |"<<=" |">>=" ;
|
|
||||||
CompareOp = '<' | "<=" | "==" | "!=" | ">=" | '>' ;
|
|
||||||
RangeOp = ".." | "..=" ;
|
|
||||||
LogicOp = "&&" | "||" | "^^" ;
|
|
||||||
|
|
||||||
BitwiseOp = '&' | '|' | '^' ;
|
Call = Index ('(' Tuple? ')')* ;
|
||||||
ShiftOp = "<<" | ">>";
|
|
||||||
TermOp = '+' | '-' ;
|
|
||||||
FactorOp = '*' | '/' | '%' ;
|
|
||||||
UnaryOp = '*' | '&' | '-' | '!' ;
|
|
||||||
|
|
||||||
(* expression::control *)
|
Index = Primary ('[' Indices ']')* ;
|
||||||
Branch = While | If | For | Break | Return | Continue ;
|
Indices = (Expr ',')* Expr? ;
|
||||||
If = "if" Expr Block (Else)? ;
|
|
||||||
While = "while" Expr Block (Else)? ;
|
Primary = Literal | Path | Array | ArrayRep | AddrOf
|
||||||
For = "for" Identifier "in" Expr Block (Else)? ;
|
| Block | Group
|
||||||
Else = "else" Expr ;
|
| 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 ;
|
Break = "break" Expr ;
|
||||||
Return = "return" Expr ;
|
Return = "return" Expr ;
|
||||||
Continue = "continue" ;
|
Continue = "continue" ;
|
||||||
|
|
||||||
|
AssignKind = '=' | '+=' | '-=' | '*=' | '/=' |
|
||||||
|
'&=' | '|=' | '^=' |'<<=' |'>>=' ;
|
||||||
|
|
||||||
|
BinaryKind = CompareOp | RangeOp | LogicOp | BitwiseOp
|
||||||
|
| ShiftOp | TermOp | FactorOp ;
|
||||||
|
CompareOp = '<' | '<=' | '==' | '!=' | '>=' | '>' ;
|
||||||
|
RangeOp = '..' | '..=' ;
|
||||||
|
LogicOp = '&&' | '||' | '^^' ;
|
||||||
|
BitwiseOp = '&' | '|' | '^' ;
|
||||||
|
ShiftOp = '<<' | '>>';
|
||||||
|
TermOp = '+' | '-' ;
|
||||||
|
FactorOp = '*' | '/' | '%' ;
|
||||||
|
|
||||||
|
UnaryKind = '*' | '-' | '!' | '@' | '#' | '~' ;
|
||||||
|
File diff suppressed because it is too large
Load Diff
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
|
//! Interprets an AST as a program
|
||||||
|
|
||||||
use crate::ast::preamble::*;
|
|
||||||
use env::Environment;
|
use env::Environment;
|
||||||
use error::{Error, IResult};
|
use error::{Error, IResult};
|
||||||
|
use interpret::Interpret;
|
||||||
use temp_type_impl::ConValue;
|
use temp_type_impl::ConValue;
|
||||||
|
|
||||||
/// Callable types can be called from within a Conlang program
|
/// Callable types can be called from within a Conlang program
|
||||||
@ -44,6 +44,8 @@ pub mod temp_type_impl {
|
|||||||
Char(char),
|
Char(char),
|
||||||
/// A string
|
/// A string
|
||||||
String(String),
|
String(String),
|
||||||
|
/// An Array
|
||||||
|
Array(Vec<ConValue>),
|
||||||
/// A tuple
|
/// A tuple
|
||||||
Tuple(Vec<ConValue>),
|
Tuple(Vec<ConValue>),
|
||||||
/// An exclusive range
|
/// An exclusive range
|
||||||
@ -75,6 +77,17 @@ pub mod temp_type_impl {
|
|||||||
};
|
};
|
||||||
Ok(Self::RangeInc(a, b))
|
Ok(Self::RangeInc(a, b))
|
||||||
}
|
}
|
||||||
|
pub fn index(&self, index: &Self) -> IResult<ConValue> {
|
||||||
|
let Self::Int(index) = index else {
|
||||||
|
Err(Error::TypeError)?
|
||||||
|
};
|
||||||
|
let Self::Array(arr) = self else {
|
||||||
|
Err(Error::TypeError)?
|
||||||
|
};
|
||||||
|
arr.get(*index as usize)
|
||||||
|
.cloned()
|
||||||
|
.ok_or(Error::OobIndex(*index as usize, arr.len()))
|
||||||
|
}
|
||||||
cmp! {
|
cmp! {
|
||||||
lt: false, <;
|
lt: false, <;
|
||||||
lt_eq: true, <=;
|
lt_eq: true, <=;
|
||||||
@ -259,6 +272,16 @@ pub mod temp_type_impl {
|
|||||||
ConValue::Bool(v) => v.fmt(f),
|
ConValue::Bool(v) => v.fmt(f),
|
||||||
ConValue::Char(v) => v.fmt(f),
|
ConValue::Char(v) => v.fmt(f),
|
||||||
ConValue::String(v) => v.fmt(f),
|
ConValue::String(v) => v.fmt(f),
|
||||||
|
ConValue::Array(array) => {
|
||||||
|
'['.fmt(f)?;
|
||||||
|
for (idx, element) in array.iter().enumerate() {
|
||||||
|
if idx > 0 {
|
||||||
|
", ".fmt(f)?
|
||||||
|
}
|
||||||
|
element.fmt(f)?
|
||||||
|
}
|
||||||
|
']'.fmt(f)
|
||||||
|
}
|
||||||
ConValue::RangeExc(a, b) => write!(f, "{a}..{}", b + 1),
|
ConValue::RangeExc(a, b) => write!(f, "{a}..{}", b + 1),
|
||||||
ConValue::RangeInc(a, b) => write!(f, "{a}..={b}"),
|
ConValue::RangeInc(a, b) => write!(f, "{a}..={b}"),
|
||||||
ConValue::Tuple(tuple) => {
|
ConValue::Tuple(tuple) => {
|
||||||
@ -282,352 +305,472 @@ pub mod temp_type_impl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A work-in-progress tree walk interpreter for Conlang
|
pub mod interpret {
|
||||||
pub trait Interpret {
|
use super::*;
|
||||||
/// Interprets this thing in the given [`Environment`].
|
use crate::ast::*;
|
||||||
///
|
/// A work-in-progress tree walk interpreter for Conlang
|
||||||
/// Everything returns a value!™
|
pub trait Interpret {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue>;
|
/// Interprets this thing in the given [`Environment`].
|
||||||
}
|
///
|
||||||
|
/// Everything returns a value!™
|
||||||
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue>;
|
||||||
|
}
|
||||||
|
|
||||||
impl Interpret for Start {
|
impl Interpret for File {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
self.0.interpret(env)
|
for item in &self.items {
|
||||||
}
|
item.interpret(env)?;
|
||||||
}
|
|
||||||
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)?,
|
|
||||||
}
|
}
|
||||||
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 Item {
|
||||||
impl Interpret for Binary {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
match &self.kind {
|
||||||
let Binary { first, other } = self;
|
ItemKind::Const(item) => item.interpret(env),
|
||||||
let mut first = first.interpret(env)?;
|
ItemKind::Static(item) => item.interpret(env),
|
||||||
for (op, other) in other {
|
ItemKind::Module(item) => item.interpret(env),
|
||||||
first = match op {
|
ItemKind::Function(item) => item.interpret(env),
|
||||||
operator::Binary::LogAnd => {
|
ItemKind::Struct(item) => item.interpret(env),
|
||||||
if first.truthy()? {
|
ItemKind::Enum(item) => item.interpret(env),
|
||||||
other.interpret(env)
|
ItemKind::Impl(item) => item.interpret(env),
|
||||||
} else {
|
}
|
||||||
return Ok(first); // Short circuiting
|
}
|
||||||
|
}
|
||||||
|
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 => {
|
ExprKind::Member(_) => todo!("Member access assignment"),
|
||||||
if !first.truthy()? {
|
ExprKind::Call(_) => todo!("Assignment to the result of a function call?"),
|
||||||
other.interpret(env)
|
ExprKind::Index(_) => todo!("Assignment to an index operation"),
|
||||||
} else {
|
ExprKind::Path(_) => todo!("Path expression resolution (IMPORTANT)"),
|
||||||
return Ok(first); // Short circuiting
|
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
|
Ok(out)
|
||||||
let (lhs, rhs) = (first.truthy()?, other.interpret(env)?.truthy()?);
|
}
|
||||||
Ok(ConValue::Bool(lhs ^ rhs))
|
}
|
||||||
|
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)?,
|
fail.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),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
impl Interpret for Else {
|
||||||
impl Interpret for FnCall {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
let Self { body } = self;
|
||||||
// evaluate the callee
|
match body {
|
||||||
let mut callee = self.callee.interpret(env)?;
|
Some(body) => body.interpret(env),
|
||||||
for args in &self.args {
|
None => Ok(ConValue::Empty),
|
||||||
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 Continue {
|
||||||
impl Interpret for Identifier {
|
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
Err(Error::Continue)
|
||||||
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 Return {
|
||||||
impl Interpret for Group {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
let Self { body } = self;
|
||||||
match self {
|
Err(Error::Return(
|
||||||
Group::Tuple(tuple) => tuple.interpret(env),
|
body.as_ref()
|
||||||
Group::Single(value) => value.interpret(env),
|
.map(|body| body.interpret(env))
|
||||||
Group::Empty => Ok(ConValue::Empty),
|
.unwrap_or(Ok(ConValue::Empty))?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
impl Interpret for Break {
|
||||||
impl Interpret for Tuple {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
let Self { body } = self;
|
||||||
Ok(ConValue::Tuple(self.elements.iter().try_fold(
|
Err(Error::Return(
|
||||||
vec![],
|
body.as_ref()
|
||||||
|mut out, element| {
|
.map(|body| body.interpret(env))
|
||||||
out.push(element.interpret(env)?);
|
.unwrap_or(Ok(ConValue::Empty))?,
|
||||||
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 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 {
|
pub mod function {
|
||||||
//! Represents a block of code which lives inside the Interpreter
|
//! Represents a block of code which lives inside the Interpreter
|
||||||
use super::{Callable, ConValue, Environment, Error, FnDecl, IResult, Identifier, Interpret};
|
use super::{Callable, ConValue, Environment, Error, IResult, Interpret};
|
||||||
use crate::ast::preamble::Name;
|
use crate::ast::{Function as FnDecl, Identifier, Param};
|
||||||
/// Represents a block of code which persists inside the Interpreter
|
/// Represents a block of code which persists inside the Interpreter
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
@ -645,22 +788,26 @@ pub mod function {
|
|||||||
|
|
||||||
impl Callable for Function {
|
impl Callable for Function {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
&self.decl.name.symbol.name
|
let FnDecl { name: Identifier(ref name), .. } = *self.decl;
|
||||||
|
name
|
||||||
}
|
}
|
||||||
fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
|
fn call(&self, env: &mut Environment, args: &[ConValue]) -> IResult<ConValue> {
|
||||||
|
let FnDecl { name: Identifier(name), args: declargs, body, rety: _ } = &*self.decl;
|
||||||
// Check arg mapping
|
// Check arg mapping
|
||||||
if args.len() != self.decl.args.len() {
|
if args.len() != declargs.len() {
|
||||||
return Err(Error::ArgNumber { want: self.decl.args.len(), got: args.len() });
|
return Err(Error::ArgNumber { want: declargs.len(), got: args.len() });
|
||||||
}
|
}
|
||||||
// TODO: Isolate cross-function scopes!
|
let Some(body) = body else {
|
||||||
// let mut env = self.env.clone();
|
return Err(Error::NotDefined(name.into()));
|
||||||
|
};
|
||||||
|
// TODO: completely refactor data storage
|
||||||
let mut frame = env.frame("fn args");
|
let mut frame = env.frame("fn args");
|
||||||
for (Name { symbol: Identifier { name, .. }, .. }, value) in
|
for (Param { mutability: _, name: Identifier(name), ty: _ }, value) in
|
||||||
self.decl.args.iter().zip(args)
|
declargs.iter().zip(args)
|
||||||
{
|
{
|
||||||
frame.insert(name, Some(value.clone()));
|
frame.insert(name, Some(value.clone()));
|
||||||
}
|
}
|
||||||
match self.decl.body.interpret(&mut frame) {
|
match body.interpret(&mut frame) {
|
||||||
Err(Error::Return(value)) => Ok(value),
|
Err(Error::Return(value)) => Ok(value),
|
||||||
Err(Error::Break(value)) => Err(Error::BadBreak(value)),
|
Err(Error::Break(value)) => Err(Error::BadBreak(value)),
|
||||||
result => result,
|
result => result,
|
||||||
@ -734,14 +881,14 @@ pub mod builtin {
|
|||||||
|
|
||||||
pub mod env {
|
pub mod env {
|
||||||
//! Lexical and non-lexical scoping for variables
|
//! Lexical and non-lexical scoping for variables
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
builtin::DEFAULT_BUILTINS,
|
builtin::DEFAULT_BUILTINS,
|
||||||
error::{Error, IResult},
|
error::{Error, IResult},
|
||||||
function::Function,
|
function::Function,
|
||||||
temp_type_impl::ConValue,
|
temp_type_impl::ConValue,
|
||||||
Callable, FnDecl, Interpret,
|
Callable, Interpret,
|
||||||
};
|
};
|
||||||
|
use crate::ast::{Function as FnDecl, Identifier};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
@ -838,10 +985,8 @@ pub mod env {
|
|||||||
}
|
}
|
||||||
/// A convenience function for registering a [FnDecl] as a [Function]
|
/// A convenience function for registering a [FnDecl] as a [Function]
|
||||||
pub fn insert_fn(&mut self, decl: &FnDecl) {
|
pub fn insert_fn(&mut self, decl: &FnDecl) {
|
||||||
let (name, function) = (
|
let FnDecl { name: Identifier(name), .. } = decl;
|
||||||
decl.name.symbol.name.clone(),
|
let (name, function) = (name.clone(), Some(Function::new(decl).into()));
|
||||||
Some(Function::new(decl).into()),
|
|
||||||
);
|
|
||||||
if let Some((frame, _)) = self.frames.last_mut() {
|
if let Some((frame, _)) = self.frames.last_mut() {
|
||||||
frame.insert(name, function);
|
frame.insert(name, function);
|
||||||
}
|
}
|
||||||
@ -898,6 +1043,7 @@ pub mod error {
|
|||||||
//! The [Error] type represents any error thrown by the [Environment](super::Environment)
|
//! The [Error] type represents any error thrown by the [Environment](super::Environment)
|
||||||
|
|
||||||
use super::temp_type_impl::ConValue;
|
use super::temp_type_impl::ConValue;
|
||||||
|
use crate::ast::Loc;
|
||||||
|
|
||||||
pub type IResult<T> = Result<T, Error>;
|
pub type IResult<T> = Result<T, Error>;
|
||||||
|
|
||||||
@ -921,6 +1067,12 @@ pub mod error {
|
|||||||
TypeError,
|
TypeError,
|
||||||
/// In clause of For loop didn't yield a Range
|
/// In clause of For loop didn't yield a Range
|
||||||
NotIterable,
|
NotIterable,
|
||||||
|
/// A value at this [location](struct@Loc) can't be indexed
|
||||||
|
NotIndexable(Loc),
|
||||||
|
/// An array index went out of bounds
|
||||||
|
OobIndex(usize, usize),
|
||||||
|
/// An expression at this [location](struct@Loc)ation is not assignable
|
||||||
|
NotAssignable(Loc),
|
||||||
/// A name was not defined in scope before being used
|
/// A name was not defined in scope before being used
|
||||||
NotDefined(String),
|
NotDefined(String),
|
||||||
/// A name was defined but not initialized
|
/// A name was defined but not initialized
|
||||||
@ -943,6 +1095,15 @@ pub mod error {
|
|||||||
Error::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
|
Error::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
|
||||||
Error::TypeError => "Incompatible types".fmt(f),
|
Error::TypeError => "Incompatible types".fmt(f),
|
||||||
Error::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
|
Error::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
|
||||||
|
Error::NotIndexable(location) => {
|
||||||
|
write!(f, "{location} expression cannot be indexed")
|
||||||
|
}
|
||||||
|
Error::OobIndex(idx, len) => {
|
||||||
|
write!(f, "Index out of bounds: index was {idx}. but len is {len}")
|
||||||
|
}
|
||||||
|
Error::NotAssignable(location) => {
|
||||||
|
write!(f, "{location} expression is not assignable")
|
||||||
|
}
|
||||||
Error::NotDefined(value) => {
|
Error::NotDefined(value) => {
|
||||||
write!(f, "{value} not bound. Did you mean `let {value};`?")
|
write!(f, "{value} not bound. Did you mean `let {value};`?")
|
||||||
}
|
}
|
||||||
@ -950,7 +1111,7 @@ pub mod error {
|
|||||||
write!(f, "{value} bound, but not initialized")
|
write!(f, "{value} bound, but not initialized")
|
||||||
}
|
}
|
||||||
Error::NotCallable(value) => {
|
Error::NotCallable(value) => {
|
||||||
write!(f, "{value} is not a function, and cannot be called")
|
write!(f, "{value} is not callable.")
|
||||||
}
|
}
|
||||||
Error::ArgNumber { want, got } => {
|
Error::ArgNumber { want, got } => {
|
||||||
write!(f, "Expected {want} arguments, got {got}")
|
write!(f, "Expected {want} arguments, got {got}")
|
||||||
|
@ -49,12 +49,30 @@ mod macros {
|
|||||||
//! env_eq!(env.x, 10); // like assert_eq! for Environments
|
//! env_eq!(env.x, 10); // like assert_eq! for Environments
|
||||||
//! ```
|
//! ```
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
use crate::interpreter::IResult;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
pub fn test_inside_block(block: &Block, env: &mut Environment) -> IResult<()> {
|
||||||
|
let Block { stmts } = block;
|
||||||
|
for stmt in stmts {
|
||||||
|
stmt.interpret(env)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Stringifies, lexes, and parses everything you give to it
|
/// Stringifies, lexes, and parses everything you give to it
|
||||||
///
|
///
|
||||||
/// Returns a `Result<`[`Start`]`, ParseError>`
|
/// Returns a `Result<`[`File`]`, ParseError>`
|
||||||
pub macro parse($($t:tt)*) {
|
pub macro file($($t:tt)*) {
|
||||||
Parser::from(Lexer::new(stringify!( $($t)* ))).parse()
|
Parser::new(Lexer::new(stringify!( $($t)* ))).file()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stringifies, lexes, and parses everything you give to it
|
||||||
|
///
|
||||||
|
/// Returns a `Result<`[`Block`]`, ParseError>`
|
||||||
|
pub macro block($($t:tt)*) {
|
||||||
|
Parser::new(Lexer::new(stringify!({ $($t)* }))).block()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates a block of code in the given environment
|
/// Evaluates a block of code in the given environment
|
||||||
@ -68,9 +86,9 @@ mod macros {
|
|||||||
/// )
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
pub macro eval($env: path, $($t:tt)*) {{
|
pub macro eval($env: path, $($t:tt)*) {{
|
||||||
parse!($($t)*)
|
test_inside_block(&block!($($t)*)
|
||||||
.expect("code passed to eval! should parse correctly")
|
.expect("code passed to eval! should parse correctly"),
|
||||||
.interpret(&mut $env)
|
&mut $env)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
/// Evaluates a block of code in the given environment, expecting the interpreter to succeed
|
/// Evaluates a block of code in the given environment, expecting the interpreter to succeed
|
||||||
@ -194,7 +212,7 @@ mod fn_declarations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod operators {
|
mod operators {
|
||||||
use crate::ast::preamble::expression::tuple;
|
use crate::ast::Tuple;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
@ -337,6 +355,7 @@ mod operators {
|
|||||||
let is_20_ne_10 = 20 != 10;
|
let is_20_ne_10 = 20 != 10;
|
||||||
let is_20_ge_10 = 20 >= 10;
|
let is_20_ge_10 = 20 >= 10;
|
||||||
let is_20_gt_10 = 20 > 10;
|
let is_20_gt_10 = 20 > 10;
|
||||||
|
dump();
|
||||||
);
|
);
|
||||||
|
|
||||||
// Less than
|
// Less than
|
||||||
|
@ -10,8 +10,6 @@ pub mod lexer;
|
|||||||
|
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
|
|
||||||
pub mod pretty_printer;
|
|
||||||
|
|
||||||
pub mod resolver;
|
pub mod resolver;
|
||||||
|
|
||||||
pub mod interpreter;
|
pub mod interpreter;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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)
|
self.get_mut(name)?.assign(name, ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(unused_macros)]
|
||||||
/// Manages a module scope
|
/// Manages a module scope
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// macro module(self, name: &str, inner: {...}) -> Result<_, Error>
|
/// macro module(self, name: &str, inner: {...}) -> Result<_, Error>
|
||||||
@ -487,372 +488,375 @@ pub trait Resolve {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mod ast1 {
|
mod ast1 {
|
||||||
#![allow(deprecated)]
|
// #![allow(deprecated)]
|
||||||
use super::*;
|
// use super::*;
|
||||||
use crate::ast::preamble::*;
|
// use crate::ast::preamble::*;
|
||||||
impl Resolve for Start {
|
// impl Resolve for Start {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Self(program) = self;
|
// let Self(program) = self;
|
||||||
program.resolve(resolver)
|
// program.resolve(resolver)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Program {
|
// impl Resolve for Program {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Self(module) = self;
|
// let Self(module) = self;
|
||||||
for decl in module {
|
// for decl in module {
|
||||||
decl.resolve(resolver)?;
|
// decl.resolve(resolver)?;
|
||||||
}
|
// }
|
||||||
// TODO: record the number of module-level assignments into the AST
|
// // TODO: record the number of module-level assignments into the AST
|
||||||
Ok(Type::Empty)
|
// Ok(Type::Empty)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Stmt {
|
// impl Resolve for Stmt {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
match self {
|
// match self {
|
||||||
Stmt::Let(value) => value.resolve(resolver),
|
// Stmt::Let(value) => value.resolve(resolver),
|
||||||
Stmt::Fn(value) => value.resolve(resolver),
|
// Stmt::Fn(value) => value.resolve(resolver),
|
||||||
Stmt::Expr(value) => value.resolve(resolver),
|
// Stmt::Expr(value) => value.resolve(resolver),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Let {
|
// impl Resolve for Let {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Let { name: Name { symbol: Identifier { name, index }, mutable, ty: _ }, init } =
|
// let Let { name: Name { symbol: Identifier { name, index }, mutable, ty: _ }, init } =
|
||||||
self;
|
// self;
|
||||||
debugln!("ty> let {name} ...");
|
// debugln!("ty> let {name} ...");
|
||||||
if let Some(init) = init {
|
// if let Some(init) = init {
|
||||||
let ty = init.resolve(resolver)?;
|
// let ty = init.resolve(resolver)?;
|
||||||
*index = Some(resolver.insert_scope(name, *mutable)?);
|
// *index = Some(resolver.insert_scope(name, *mutable)?);
|
||||||
resolver.get_mut(name)?.assign(name, &ty)?;
|
// resolver.get_mut(name)?.assign(name, &ty)?;
|
||||||
} else {
|
// } else {
|
||||||
resolver.insert_scope(name, *mutable)?;
|
// resolver.insert_scope(name, *mutable)?;
|
||||||
}
|
// }
|
||||||
Ok(Type::Empty)
|
// Ok(Type::Empty)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for FnDecl {
|
// impl Resolve for FnDecl {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let FnDecl { name: Name { symbol: Identifier { name, index }, .. }, args, body } = self;
|
// let FnDecl { name: Name { symbol: Identifier { name, index }, .. }, args, body } =
|
||||||
debugln!("ty> fn {name} ...");
|
// self; debugln!("ty> fn {name} ...");
|
||||||
// register the name at module scope
|
// // register the name at module scope
|
||||||
*index = Some(resolver.insert_module(name, false)?);
|
// *index = Some(resolver.insert_module(name, false)?);
|
||||||
// create a new lexical scope
|
// // create a new lexical scope
|
||||||
let scopes = std::mem::take(&mut resolver.scopes);
|
// let scopes = std::mem::take(&mut resolver.scopes);
|
||||||
// type-check the function body
|
// // type-check the function body
|
||||||
let out = {
|
// let out = {
|
||||||
let mut resolver = resolver.frame();
|
// let mut resolver = resolver.frame();
|
||||||
let mut evaluated_args = vec![];
|
// let mut evaluated_args = vec![];
|
||||||
for arg in args {
|
// for arg in args {
|
||||||
evaluated_args.push(arg.resolve(&mut resolver)?)
|
// evaluated_args.push(arg.resolve(&mut resolver)?)
|
||||||
}
|
// }
|
||||||
let fn_decl = Type::Fn { args: evaluated_args.clone(), ret: Box::new(Type::Empty) };
|
// let fn_decl = Type::Fn { args: evaluated_args.clone(), ret: Box::new(Type::Empty)
|
||||||
resolver.get_mut(name)?.assign(name, &fn_decl)?;
|
// }; resolver.get_mut(name)?.assign(name, &fn_decl)?;
|
||||||
module!(resolver, name, { body.resolve(&mut resolver) })
|
// module!(resolver, name, { body.resolve(&mut resolver) })
|
||||||
};
|
// };
|
||||||
let _ = std::mem::replace(&mut resolver.scopes, scopes);
|
// let _ = std::mem::replace(&mut resolver.scopes, scopes);
|
||||||
out
|
// out
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Name {
|
// impl Resolve for Name {
|
||||||
fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
Ok(Type::Empty)
|
// Ok(Type::Empty)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Block {
|
// impl Resolve for Block {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Block { let_count: _, statements, expr } = self;
|
// let Block { let_count: _, statements, expr } = self;
|
||||||
let mut resolver = resolver.frame();
|
// let mut resolver = resolver.frame();
|
||||||
for stmt in statements {
|
// for stmt in statements {
|
||||||
stmt.resolve(&mut resolver)?;
|
// stmt.resolve(&mut resolver)?;
|
||||||
}
|
// }
|
||||||
expr.resolve(&mut resolver)
|
// expr.resolve(&mut resolver)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Expr {
|
// impl Resolve for Expr {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Expr(expr) = self;
|
// let Expr(expr) = self;
|
||||||
expr.resolve(resolver)
|
// expr.resolve(resolver)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Resolve for Operation {
|
// impl Resolve for Operation {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
match self {
|
// match self {
|
||||||
Operation::Assign(value) => value.resolve(resolver),
|
// Operation::Assign(value) => value.resolve(resolver),
|
||||||
Operation::Binary(value) => value.resolve(resolver),
|
// Operation::Binary(value) => value.resolve(resolver),
|
||||||
Operation::Unary(value) => value.resolve(resolver),
|
// Operation::Unary(value) => value.resolve(resolver),
|
||||||
Operation::Call(value) => value.resolve(resolver),
|
// Operation::Call(value) => value.resolve(resolver),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Assign {
|
// impl Resolve for Assign {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Assign { target, operator, init } = self;
|
// let Assign { target, operator, init } = self;
|
||||||
// Evaluate the initializer expression
|
// // Evaluate the initializer expression
|
||||||
let ty = init.resolve(resolver)?;
|
// let ty = init.resolve(resolver)?;
|
||||||
// Resolve the variable
|
// // Resolve the variable
|
||||||
match (operator, resolver.get_mut(&target.name)?) {
|
// match (operator, resolver.get_mut(&target.name)?) {
|
||||||
(
|
// (
|
||||||
operator::Assign::Assign,
|
// operator::Assign::Assign,
|
||||||
Variable { status: Status::Initialized(_), mutable: false, index },
|
// Variable { status: Status::Initialized(_), mutable: false, index },
|
||||||
) => Err(Error::ImmutableAssign(target.name.clone(), *index)),
|
// ) => Err(Error::ImmutableAssign(target.name.clone(), *index)),
|
||||||
// TODO: make typing more expressive for modifying assignment
|
// // TODO: make typing more expressive for modifying assignment
|
||||||
(_, variable) => variable
|
// (_, variable) => variable
|
||||||
.modify_assign(&target.name, &ty)
|
// .modify_assign(&target.name, &ty)
|
||||||
.map(|_| Type::Empty),
|
// .map(|_| Type::Empty),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Resolve for Binary {
|
// impl Resolve for Binary {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Binary { first, other } = self;
|
// let Binary { first, other } = self;
|
||||||
|
|
||||||
let mut first = first.resolve(resolver)?;
|
// let mut first = first.resolve(resolver)?;
|
||||||
for (op, other) in other {
|
// for (op, other) in other {
|
||||||
let other = other.resolve(resolver)?;
|
// let other = other.resolve(resolver)?;
|
||||||
first = resolver.resolve_binary_operator(first, other, op)?;
|
// first = resolver.resolve_binary_operator(first, other, op)?;
|
||||||
}
|
// }
|
||||||
Ok(first)
|
// Ok(first)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Unary {
|
// impl Resolve for Unary {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Unary { operators, operand } = self;
|
// let Unary { operators, operand } = self;
|
||||||
let mut operand = operand.resolve(resolver)?;
|
// let mut operand = operand.resolve(resolver)?;
|
||||||
for op in operators {
|
// for op in operators {
|
||||||
operand = resolver.resolve_unary_operator(operand, op)?;
|
// operand = resolver.resolve_unary_operator(operand, op)?;
|
||||||
}
|
// }
|
||||||
Ok(operand)
|
// Ok(operand)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
/// Resolve [operator]s
|
// /// Resolve [operator]s
|
||||||
impl Resolver {
|
// impl Resolver {
|
||||||
fn resolve_binary_operator(
|
// fn resolve_binary_operator(
|
||||||
&mut self,
|
// &mut self,
|
||||||
first: Type,
|
// first: Type,
|
||||||
other: Type,
|
// other: Type,
|
||||||
op: &operator::Binary,
|
// op: &operator::Binary,
|
||||||
) -> TyResult<Type> {
|
// ) -> TyResult<Type> {
|
||||||
// TODO: check type compatibility for binary ops
|
// // TODO: check type compatibility for binary ops
|
||||||
// TODO: desugar binary ops into function calls, when member functions are a thing
|
// // TODO: desugar binary ops into function calls, when member functions are a thing
|
||||||
eprintln!("Resolve binary operators {first} {op:?} {other}");
|
// eprintln!("Resolve binary operators {first} {op:?} {other}");
|
||||||
if first != other {
|
// if first != other {
|
||||||
Err(Error::TypeMismatch { want: first, got: other })
|
// Err(Error::TypeMismatch { want: first, got: other })
|
||||||
} else {
|
// } else {
|
||||||
Ok(first)
|
// Ok(first)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
fn resolve_unary_operator(
|
// fn resolve_unary_operator(
|
||||||
&mut self,
|
// &mut self,
|
||||||
operand: Type,
|
// operand: Type,
|
||||||
op: &operator::Unary,
|
// op: &operator::Unary,
|
||||||
) -> TyResult<Type> {
|
// ) -> TyResult<Type> {
|
||||||
// TODO: Allow more expressive unary operator type conversions
|
// // TODO: Allow more expressive unary operator type conversions
|
||||||
todo!("Resolve unary operators {op:?} {operand}")
|
// todo!("Resolve unary operators {op:?} {operand}")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Call {
|
// impl Resolve for Call {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
match self {
|
// match self {
|
||||||
Call::FnCall(value) => value.resolve(resolver),
|
// Call::FnCall(value) => value.resolve(resolver),
|
||||||
Call::Primary(value) => value.resolve(resolver),
|
// Call::Primary(value) => value.resolve(resolver),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for FnCall {
|
// impl Resolve for FnCall {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let FnCall { callee, args } = self;
|
// let FnCall { callee, args } = self;
|
||||||
let mut callee = callee.resolve(resolver)?;
|
// let mut callee = callee.resolve(resolver)?;
|
||||||
for argset in args {
|
// for argset in args {
|
||||||
// arguments should always be a tuple here
|
// // arguments should always be a tuple here
|
||||||
let arguments = argset.resolve(resolver)?;
|
// let arguments = argset.resolve(resolver)?;
|
||||||
let Type::Tuple(arguments) = arguments else {
|
// let Type::Tuple(arguments) = arguments else {
|
||||||
Err(Error::TypeMismatch {
|
// Err(Error::TypeMismatch {
|
||||||
want: Type::Tuple(vec![Type::ManyInferred]),
|
// want: Type::Tuple(vec![Type::ManyInferred]),
|
||||||
got: arguments,
|
// got: arguments,
|
||||||
})?
|
// })?
|
||||||
};
|
// };
|
||||||
// Verify that the callee is a function, and the arguments match.
|
// // Verify that the callee is a function, and the arguments match.
|
||||||
// We need the arguments
|
// // We need the arguments
|
||||||
let Type::Fn { args, ret } = callee else {
|
// let Type::Fn { args, ret } = callee else {
|
||||||
return Err(Error::TypeMismatch {
|
// return Err(Error::TypeMismatch {
|
||||||
want: Type::Fn { args: arguments, ret: Type::Inferred.into() },
|
// want: Type::Fn { args: arguments, ret: Type::Inferred.into() },
|
||||||
got: callee,
|
// got: callee,
|
||||||
})?;
|
// })?;
|
||||||
};
|
// };
|
||||||
for (want, got) in args.iter().zip(&arguments) {
|
// for (want, got) in args.iter().zip(&arguments) {
|
||||||
// TODO: verify generics
|
// // TODO: verify generics
|
||||||
if let Type::Generic(_) = want {
|
// if let Type::Generic(_) = want {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
if want != got {
|
// if want != got {
|
||||||
return Err(Error::TypeMismatch {
|
// return Err(Error::TypeMismatch {
|
||||||
want: Type::Fn { args: arguments, ret: Type::Inferred.into() },
|
// want: Type::Fn { args: arguments, ret: Type::Inferred.into() },
|
||||||
got: Type::Fn { args, ret },
|
// got: Type::Fn { args, ret },
|
||||||
})?;
|
// })?;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
callee = *ret;
|
// callee = *ret;
|
||||||
}
|
// }
|
||||||
Ok(callee)
|
// Ok(callee)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Primary {
|
// impl Resolve for Primary {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
match self {
|
// match self {
|
||||||
Primary::Identifier(value) => value.resolve(resolver),
|
// Primary::Identifier(value) => value.resolve(resolver),
|
||||||
Primary::Literal(value) => value.resolve(resolver),
|
// Primary::Literal(value) => value.resolve(resolver),
|
||||||
Primary::Block(value) => value.resolve(resolver),
|
// Primary::Block(value) => value.resolve(resolver),
|
||||||
Primary::Group(value) => value.resolve(resolver),
|
// Primary::Group(value) => value.resolve(resolver),
|
||||||
Primary::Branch(value) => value.resolve(resolver),
|
// Primary::Branch(value) => value.resolve(resolver),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Resolve for Group {
|
// impl Resolve for Group {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
match self {
|
// match self {
|
||||||
Group::Tuple(tuple) => tuple.resolve(resolver),
|
// Group::Tuple(tuple) => tuple.resolve(resolver),
|
||||||
Group::Single(expr) => expr.resolve(resolver),
|
// Group::Single(expr) => expr.resolve(resolver),
|
||||||
Group::Empty => Ok(Type::Empty),
|
// Group::Empty => Ok(Type::Empty),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Resolve for Tuple {
|
// impl Resolve for Tuple {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Tuple { elements } = self;
|
// let Tuple { elements } = self;
|
||||||
let mut types = vec![];
|
// let mut types = vec![];
|
||||||
for expr in elements.iter_mut() {
|
// for expr in elements.iter_mut() {
|
||||||
types.push(expr.resolve(resolver)?);
|
// types.push(expr.resolve(resolver)?);
|
||||||
}
|
// }
|
||||||
Ok(Type::Tuple(types))
|
// Ok(Type::Tuple(types))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Resolve for Identifier {
|
// impl Resolve for Identifier {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Identifier { name, index: id_index } = self;
|
// let Identifier { name, index: id_index } = self;
|
||||||
let Variable { index, status, .. } = resolver.get(name)?;
|
// let Variable { index, status, .. } = resolver.get(name)?;
|
||||||
*id_index = Some(*index);
|
// *id_index = Some(*index);
|
||||||
let ty = match status {
|
// let ty = match status {
|
||||||
Status::Initialized(t) => t,
|
// Status::Initialized(t) => t,
|
||||||
_ => Err(Error::Uninitialized(name.to_owned(), *index))?,
|
// _ => Err(Error::Uninitialized(name.to_owned(), *index))?,
|
||||||
};
|
// };
|
||||||
debugln!("ty> Resolved {} #{index}: {ty}", name);
|
// debugln!("ty> Resolved {} #{index}: {ty}", name);
|
||||||
Ok(ty.to_owned())
|
// Ok(ty.to_owned())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Literal {
|
// impl Resolve for Literal {
|
||||||
fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
Ok(match self {
|
// Ok(match self {
|
||||||
Literal::String(_) => Type::String,
|
// Literal::String(_) => Type::String,
|
||||||
Literal::Char(_) => Type::Char,
|
// Literal::Char(_) => Type::Char,
|
||||||
Literal::Bool(_) => Type::Bool,
|
// Literal::Bool(_) => Type::Bool,
|
||||||
Literal::Float(_) => Type::Float,
|
// Literal::Float(_) => Type::Float,
|
||||||
Literal::Int(_) => Type::Int,
|
// Literal::Int(_) => Type::Int,
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Resolve for Flow {
|
// impl Resolve for Flow {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
// TODO: Finish this
|
// // TODO: Finish this
|
||||||
match self {
|
// match self {
|
||||||
Flow::While(value) => value.resolve(resolver),
|
// Flow::While(value) => value.resolve(resolver),
|
||||||
Flow::If(value) => value.resolve(resolver),
|
// Flow::If(value) => value.resolve(resolver),
|
||||||
Flow::For(value) => value.resolve(resolver),
|
// Flow::For(value) => value.resolve(resolver),
|
||||||
Flow::Continue(value) => value.resolve(resolver),
|
// Flow::Continue(value) => value.resolve(resolver),
|
||||||
Flow::Return(value) => value.resolve(resolver),
|
// Flow::Return(value) => value.resolve(resolver),
|
||||||
Flow::Break(value) => value.resolve(resolver),
|
// Flow::Break(value) => value.resolve(resolver),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for While {
|
// impl Resolve for While {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
// TODO: Finish this
|
// // TODO: Finish this
|
||||||
// Visit else first, save that to a break-pattern stack in the Resolver,
|
// // Visit else first, save that to a break-pattern stack in the Resolver,
|
||||||
// and check it inside Break::resolve()
|
// // and check it inside Break::resolve()
|
||||||
let While { cond, body, else_ } = self;
|
// let While { cond, body, else_ } = self;
|
||||||
cond.resolve(resolver)?; // must be Type::Bool
|
// cond.resolve(resolver)?; // must be Type::Bool
|
||||||
body.resolve(resolver)?; // discard
|
// body.resolve(resolver)?; // discard
|
||||||
else_.resolve(resolver) // compare with returns inside body
|
// else_.resolve(resolver) // compare with returns inside body
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for If {
|
// impl Resolve for If {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let If { cond, body, else_ } = self;
|
// let If { cond, body, else_ } = self;
|
||||||
let cond = cond.resolve(resolver)?;
|
// let cond = cond.resolve(resolver)?;
|
||||||
if Type::Bool != cond {
|
// if Type::Bool != cond {
|
||||||
return Err(Error::TypeMismatch { want: Type::Bool, got: cond });
|
// return Err(Error::TypeMismatch { want: Type::Bool, got: cond });
|
||||||
}
|
// }
|
||||||
let body_ty = body.resolve(resolver)?;
|
// let body_ty = body.resolve(resolver)?;
|
||||||
let else_ty = else_.resolve(resolver)?;
|
// let else_ty = else_.resolve(resolver)?;
|
||||||
if body_ty == else_ty {
|
// if body_ty == else_ty {
|
||||||
Ok(body_ty)
|
// Ok(body_ty)
|
||||||
} else {
|
// } else {
|
||||||
Err(Error::TypeMismatch { want: body_ty, got: else_ty })
|
// Err(Error::TypeMismatch { want: body_ty, got: else_ty })
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Resolve for For {
|
// impl Resolve for For {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let For { var: Identifier { name, index }, iter, body, else_ } = self;
|
// let For { var: Identifier { name, index }, iter, body, else_ } = self;
|
||||||
debugln!("> for {name} in ...");
|
// debugln!("> for {name} in ...");
|
||||||
// Visit the iter expression and get its type
|
// // Visit the iter expression and get its type
|
||||||
let range = iter.resolve(resolver)?;
|
// let range = iter.resolve(resolver)?;
|
||||||
let ty = match range {
|
// let ty = match range {
|
||||||
Type::Range(t) => t,
|
// Type::Range(t) => t,
|
||||||
got => Err(Error::TypeMismatch { want: Type::Range(Type::Inferred.into()), got })?,
|
// got => Err(Error::TypeMismatch { want: Type::Range(Type::Inferred.into()), got
|
||||||
};
|
// })?, };
|
||||||
let body_ty = {
|
// let body_ty = {
|
||||||
let mut resolver = resolver.frame();
|
// let mut resolver = resolver.frame();
|
||||||
// bind the variable in the loop scope
|
// // bind the variable in the loop scope
|
||||||
*index = Some(resolver.insert_scope(name, false)?);
|
// *index = Some(resolver.insert_scope(name, false)?);
|
||||||
resolver.get_mut(name)?.assign(name, &ty)?;
|
// resolver.get_mut(name)?.assign(name, &ty)?;
|
||||||
body.resolve(&mut resolver)
|
// body.resolve(&mut resolver)
|
||||||
}?;
|
// }?;
|
||||||
// visit the else block
|
// // visit the else block
|
||||||
let else_ty = else_.resolve(resolver)?;
|
// let else_ty = else_.resolve(resolver)?;
|
||||||
if body_ty != else_ty {
|
// if body_ty != else_ty {
|
||||||
Err(Error::TypeMismatch { want: body_ty, got: else_ty })
|
// Err(Error::TypeMismatch { want: body_ty, got: else_ty })
|
||||||
} else {
|
// } else {
|
||||||
Ok(body_ty)
|
// Ok(body_ty)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Else {
|
// impl Resolve for Else {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
let Else { expr } = self;
|
// let Else { expr } = self;
|
||||||
expr.resolve(resolver)
|
// expr.resolve(resolver)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Resolve for Continue {
|
// impl Resolve for Continue {
|
||||||
fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, _resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
// TODO: Finish control flow
|
// // TODO: Finish control flow
|
||||||
Ok(Type::Never)
|
// Ok(Type::Never)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Break {
|
// impl Resolve for Break {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
// TODO: Finish control flow
|
// // TODO: Finish control flow
|
||||||
let Break { expr } = self;
|
// let Break { expr } = self;
|
||||||
expr.resolve(resolver)
|
// expr.resolve(resolver)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
impl Resolve for Return {
|
// impl Resolve for Return {
|
||||||
fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
// fn resolve(&mut self, resolver: &mut Resolver) -> TyResult<Type> {
|
||||||
// TODO: Finish control flow
|
// // TODO: Finish control flow
|
||||||
let Return { expr } = self;
|
// let Return { expr } = self;
|
||||||
expr.resolve(resolver)
|
// expr.resolve(resolver)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
mod ast2 {}
|
mod ast {
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
use crate::ast::*;
|
||||||
|
}
|
||||||
|
|
||||||
// heakc yea man, generics
|
// heakc yea man, generics
|
||||||
impl<T: Resolve> Resolve for Option<T> {
|
impl<T: Resolve> Resolve for Option<T> {
|
||||||
|
@ -78,6 +78,7 @@ pub enum Type {
|
|||||||
pub enum Keyword {
|
pub enum Keyword {
|
||||||
Break,
|
Break,
|
||||||
Cl,
|
Cl,
|
||||||
|
Const,
|
||||||
Continue,
|
Continue,
|
||||||
Else,
|
Else,
|
||||||
Enum,
|
Enum,
|
||||||
@ -85,13 +86,16 @@ pub enum Keyword {
|
|||||||
For,
|
For,
|
||||||
Fn,
|
Fn,
|
||||||
If,
|
If,
|
||||||
|
Impl,
|
||||||
In,
|
In,
|
||||||
Let,
|
Let,
|
||||||
Mod,
|
Mod,
|
||||||
Mut,
|
Mut,
|
||||||
|
Pub,
|
||||||
Return,
|
Return,
|
||||||
SelfKw,
|
SelfKw,
|
||||||
SelfTy,
|
SelfTy,
|
||||||
|
Static,
|
||||||
Struct,
|
Struct,
|
||||||
Super,
|
Super,
|
||||||
True,
|
True,
|
||||||
@ -172,6 +176,7 @@ impl Display for Keyword {
|
|||||||
match self {
|
match self {
|
||||||
Self::Break => "break".fmt(f),
|
Self::Break => "break".fmt(f),
|
||||||
Self::Cl => "cl".fmt(f),
|
Self::Cl => "cl".fmt(f),
|
||||||
|
Self::Const => "const".fmt(f),
|
||||||
Self::Continue => "continue".fmt(f),
|
Self::Continue => "continue".fmt(f),
|
||||||
Self::Else => "else".fmt(f),
|
Self::Else => "else".fmt(f),
|
||||||
Self::Enum => "enum".fmt(f),
|
Self::Enum => "enum".fmt(f),
|
||||||
@ -179,13 +184,16 @@ impl Display for Keyword {
|
|||||||
Self::For => "for".fmt(f),
|
Self::For => "for".fmt(f),
|
||||||
Self::Fn => "fn".fmt(f),
|
Self::Fn => "fn".fmt(f),
|
||||||
Self::If => "if".fmt(f),
|
Self::If => "if".fmt(f),
|
||||||
|
Self::Impl => "impl".fmt(f),
|
||||||
Self::In => "in".fmt(f),
|
Self::In => "in".fmt(f),
|
||||||
Self::Let => "let".fmt(f),
|
Self::Let => "let".fmt(f),
|
||||||
Self::Mod => "mod".fmt(f),
|
Self::Mod => "mod".fmt(f),
|
||||||
Self::Mut => "mut".fmt(f),
|
Self::Mut => "mut".fmt(f),
|
||||||
|
Self::Pub => "pub".fmt(f),
|
||||||
Self::Return => "return".fmt(f),
|
Self::Return => "return".fmt(f),
|
||||||
Self::SelfKw => "self".fmt(f),
|
Self::SelfKw => "self".fmt(f),
|
||||||
Self::SelfTy => "Self".fmt(f),
|
Self::SelfTy => "Self".fmt(f),
|
||||||
|
Self::Static => "static".fmt(f),
|
||||||
Self::Struct => "struct".fmt(f),
|
Self::Struct => "struct".fmt(f),
|
||||||
Self::Super => "super".fmt(f),
|
Self::Super => "super".fmt(f),
|
||||||
Self::True => "true".fmt(f),
|
Self::True => "true".fmt(f),
|
||||||
@ -200,6 +208,7 @@ impl FromStr for Keyword {
|
|||||||
Ok(match s {
|
Ok(match s {
|
||||||
"break" => Self::Break,
|
"break" => Self::Break,
|
||||||
"cl" => Self::Cl,
|
"cl" => Self::Cl,
|
||||||
|
"const" => Self::Const,
|
||||||
"continue" => Self::Continue,
|
"continue" => Self::Continue,
|
||||||
"else" => Self::Else,
|
"else" => Self::Else,
|
||||||
"enum" => Self::Enum,
|
"enum" => Self::Enum,
|
||||||
@ -207,13 +216,16 @@ impl FromStr for Keyword {
|
|||||||
"for" => Self::For,
|
"for" => Self::For,
|
||||||
"fn" => Self::Fn,
|
"fn" => Self::Fn,
|
||||||
"if" => Self::If,
|
"if" => Self::If,
|
||||||
|
"impl" => Self::Impl,
|
||||||
"in" => Self::In,
|
"in" => Self::In,
|
||||||
"let" => Self::Let,
|
"let" => Self::Let,
|
||||||
"mod" => Self::Mod,
|
"mod" => Self::Mod,
|
||||||
"mut" => Self::Mut,
|
"mut" => Self::Mut,
|
||||||
|
"pub" => Self::Pub,
|
||||||
"return" => Self::Return,
|
"return" => Self::Return,
|
||||||
"self" => Self::SelfKw,
|
"self" => Self::SelfKw,
|
||||||
"Self" => Self::SelfTy,
|
"Self" => Self::SelfTy,
|
||||||
|
"static" => Self::Static,
|
||||||
"struct" => Self::Struct,
|
"struct" => Self::Struct,
|
||||||
"super" => Self::Super,
|
"super" => Self::Super,
|
||||||
"true" => Self::True,
|
"true" => Self::True,
|
||||||
|
Loading…
Reference in New Issue
Block a user