work
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
use crate::parser::{DisplayCtx, FmtNode};
|
||||
|
||||
use super::Token;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
@@ -24,3 +26,9 @@ impl std::fmt::Display for Lit {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FmtNode for Lit {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter, _: DisplayCtx) -> std::fmt::Result {
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@ impl<'a> Cursor<'a> {
|
||||
self.next().ok_or_else(CompilerMsg::unexpected_eof)
|
||||
}
|
||||
|
||||
pub fn expect_peek(&self) -> Result<&Token, CompilerMsg> {
|
||||
self.peek().ok_or_else(CompilerMsg::unexpected_eof)
|
||||
}
|
||||
|
||||
pub fn expect(&mut self, token: Token) -> Result<Token, CompilerMsg> {
|
||||
let next = self.expect_next()?;
|
||||
if next == token {
|
||||
|
||||
@@ -28,6 +28,8 @@ def_tokens! {
|
||||
Hash: "#",
|
||||
}
|
||||
keyword {
|
||||
Let: "let",
|
||||
Do: "do",
|
||||
Fn: "fn",
|
||||
If: "if",
|
||||
Loop: "loop",
|
||||
|
||||
@@ -15,7 +15,7 @@ pub trait Parsable: Sized + Node {
|
||||
pub struct ParseCtx<'a> {
|
||||
start: usize,
|
||||
cursor: Cursor<'a>,
|
||||
nodes: Nodes,
|
||||
pub nodes: Nodes,
|
||||
}
|
||||
|
||||
impl<'a> ParseCtx<'a> {
|
||||
|
||||
+27
-10
@@ -1,13 +1,13 @@
|
||||
use super::*;
|
||||
|
||||
pub struct Body {
|
||||
pub exprs: Vec<Id<Expr>>,
|
||||
pub items: Vec<Id<Item>>,
|
||||
pub final_semicolon: bool,
|
||||
}
|
||||
|
||||
impl Parsable for Body {
|
||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
||||
let mut exprs = Vec::new();
|
||||
let mut items = Vec::new();
|
||||
fn at_end(ctx: &mut ParseCtx) -> bool {
|
||||
ctx.peek().is_none_or(|t| *t == Token::CloseCurly)
|
||||
}
|
||||
@@ -15,14 +15,19 @@ impl Parsable for Body {
|
||||
if at_end(ctx) {
|
||||
break true;
|
||||
}
|
||||
exprs.push(ctx.parse()?);
|
||||
let item: Id<Item> = ctx.parse()?;
|
||||
let needs_semicolon = item.needs_semicolon(&ctx.nodes);
|
||||
items.push(item);
|
||||
if at_end(ctx) {
|
||||
break false;
|
||||
}
|
||||
if needs_semicolon {
|
||||
ctx.expect(Token::Semicolon)?;
|
||||
}
|
||||
while ctx.next_if(Token::Semicolon) {}
|
||||
};
|
||||
Ok(Self {
|
||||
exprs,
|
||||
items,
|
||||
final_semicolon,
|
||||
})
|
||||
}
|
||||
@@ -31,15 +36,27 @@ impl Parsable for Body {
|
||||
impl FmtNode for Body {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result {
|
||||
// surely there's a better way to do this
|
||||
if let Some((last, rest)) = self.exprs.split_last() {
|
||||
if let Some((last, rest)) = self.items.split_last() {
|
||||
for &i in rest {
|
||||
writeln!(f, "{}{};", " ".repeat(ctx.indent), i.dsp(ctx))?;
|
||||
}
|
||||
if self.final_semicolon {
|
||||
writeln!(f, "{}{};", " ".repeat(ctx.indent), last.dsp(ctx))?;
|
||||
writeln!(
|
||||
f,
|
||||
"{}{}{}",
|
||||
" ".repeat(ctx.indent),
|
||||
i.dsp(ctx),
|
||||
if i.needs_semicolon(ctx.nodes) {
|
||||
";"
|
||||
} else {
|
||||
writeln!(f, "{}{}", " ".repeat(ctx.indent), last.dsp(ctx))?;
|
||||
""
|
||||
}
|
||||
)?;
|
||||
}
|
||||
writeln!(
|
||||
f,
|
||||
"{}{}{}",
|
||||
" ".repeat(ctx.indent),
|
||||
last.dsp(ctx),
|
||||
if self.final_semicolon { ";" } else { "" }
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+27
-37
@@ -16,11 +16,6 @@ pub enum Expr {
|
||||
target: Id<Expr>,
|
||||
val: Id<Expr>,
|
||||
},
|
||||
Define {
|
||||
target: Id<Expr>,
|
||||
ty: Option<Id<Type>>,
|
||||
val: Id<Expr>,
|
||||
},
|
||||
If {
|
||||
cond: Id<Expr>,
|
||||
body: Id<Expr>,
|
||||
@@ -45,16 +40,6 @@ impl Parsable for Expr {
|
||||
let val = ctx.parse_with(Self::unit)?;
|
||||
Expr::Assign { target, val }
|
||||
}
|
||||
Token::Colon => {
|
||||
let target = ctx.push_adv(res);
|
||||
let mut ty = None;
|
||||
if !ctx.next_if(Token::Equal) {
|
||||
ty = Some(ctx.parse()?);
|
||||
ctx.expect(Token::Equal)?;
|
||||
}
|
||||
let val = ctx.parse_with(Self::unit)?;
|
||||
Expr::Define { target, ty, val }
|
||||
}
|
||||
Token::OpenParen => {
|
||||
let target = ctx.push_adv(res);
|
||||
let args = ctx.list(Token::Comma, Token::CloseParen)?;
|
||||
@@ -76,12 +61,12 @@ impl Expr {
|
||||
Token::Fn => Self::Fn(ctx.parse()?),
|
||||
Token::If => {
|
||||
let cond = ctx.parse()?;
|
||||
let body = cond_body(cond, ctx)?;
|
||||
let body = cond_body(ctx)?;
|
||||
Self::If { cond, body }
|
||||
}
|
||||
Token::While => {
|
||||
let cond = ctx.parse()?;
|
||||
let body = cond_body(cond, ctx)?;
|
||||
let body = cond_body(ctx)?;
|
||||
Self::While { cond, body }
|
||||
}
|
||||
Token::Loop => {
|
||||
@@ -110,6 +95,10 @@ impl Expr {
|
||||
matches!(self, Expr::Group(_))
|
||||
}
|
||||
|
||||
pub fn is_block(&self) -> bool {
|
||||
matches!(self, Expr::Block(_))
|
||||
}
|
||||
|
||||
pub fn block(ctx: &mut ParseCtx) -> Result<Expr, CompilerMsg> {
|
||||
ctx.expect(Token::OpenCurly)?;
|
||||
let id = ctx.parse()?;
|
||||
@@ -118,16 +107,32 @@ impl Expr {
|
||||
}
|
||||
}
|
||||
|
||||
fn cond_body(cond: Id<Expr>, ctx: &mut ParseCtx) -> Result<Id<Expr>, CompilerMsg> {
|
||||
if ctx[cond].is_group() {
|
||||
fn cond_body(ctx: &mut ParseCtx) -> Result<Id<Expr>, CompilerMsg> {
|
||||
if ctx.next_if(Token::Do) {
|
||||
ctx.parse()
|
||||
} else {
|
||||
ctx.parse_with(Expr::block)
|
||||
}
|
||||
}
|
||||
|
||||
impl Id<Expr> {
|
||||
pub fn ends_with_block(&self, nodes: &Nodes) -> bool {
|
||||
match nodes[self] {
|
||||
Expr::Block(..) => true,
|
||||
Expr::Loop { body }
|
||||
| Expr::While { body, .. }
|
||||
| Expr::If { body, .. }
|
||||
| Expr::Negate(body)
|
||||
| Expr::Assign { val: body, .. } => body.ends_with_block(nodes),
|
||||
Expr::Fn(f) => f.ends_with_block(nodes),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FmtNode for Expr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter, mut ctx: DisplayCtx) -> std::fmt::Result {
|
||||
let do_ = |id: Id<Expr>| if ctx.nodes[id].is_block() { "" } else { "do " };
|
||||
match *self {
|
||||
Self::Ident(id) => id.fmt(f, ctx),
|
||||
Self::Group(id) => write!(f, "({})", id.dsp(ctx)),
|
||||
@@ -142,27 +147,18 @@ impl FmtNode for Expr {
|
||||
Self::Assign { target, val } => {
|
||||
write!(f, "{} = {}", target.dsp(ctx), val.dsp(ctx))
|
||||
}
|
||||
Self::Define { target, ty, val } => {
|
||||
target.fmt(f, ctx)?;
|
||||
if let Some(ty) = ty {
|
||||
write!(f, ": {} ", ty.dsp(ctx))?;
|
||||
} else {
|
||||
write!(f, " :")?;
|
||||
}
|
||||
write!(f, "= {}", val.dsp(ctx))
|
||||
}
|
||||
Self::If { cond, body } => {
|
||||
write!(f, "if {} {}", cond.dsp(ctx), body.dsp(ctx))
|
||||
write!(f, "if {} {}{}", cond.dsp(ctx), do_(body), body.dsp(ctx))
|
||||
}
|
||||
Self::While { cond, body } => {
|
||||
write!(f, "while {} {}", cond.dsp(ctx), body.dsp(ctx))
|
||||
write!(f, "while {} {}{}", cond.dsp(ctx), do_(body), body.dsp(ctx))
|
||||
}
|
||||
Self::Loop { body } => {
|
||||
write!(f, "loop {}", body.dsp(ctx))
|
||||
}
|
||||
Self::Block(body) => {
|
||||
write!(f, "{{")?;
|
||||
if !ctx.nodes[body].exprs.is_empty() {
|
||||
if !ctx.nodes[body].items.is_empty() {
|
||||
writeln!(f)?;
|
||||
ctx.indent += 3;
|
||||
body.fmt(f, ctx)?;
|
||||
@@ -173,9 +169,3 @@ impl FmtNode for Expr {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FmtNode for Lit {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter, _: DisplayCtx) -> std::fmt::Result {
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,3 +40,9 @@ impl FmtNode for Func {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Id<Func> {
|
||||
pub fn ends_with_block(&self, nodes: &Nodes) -> bool {
|
||||
nodes[self].body.ends_with_block(nodes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
use super::*;
|
||||
|
||||
pub enum Item {
|
||||
Let {
|
||||
name: Id<Ident>,
|
||||
ty: Option<Id<Type>>,
|
||||
val: Id<Expr>,
|
||||
},
|
||||
Struct(Id<Struct>),
|
||||
Expr(Id<Expr>),
|
||||
}
|
||||
|
||||
impl Parsable for Item {
|
||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
||||
Ok(match ctx.expect_peek()? {
|
||||
Token::Let => {
|
||||
ctx.next();
|
||||
let name = ctx.parse()?;
|
||||
let mut ty = None;
|
||||
if ctx.next_if(Token::Colon) {
|
||||
ty = Some(ctx.parse()?);
|
||||
}
|
||||
ctx.expect(Token::Equal)?;
|
||||
let val = ctx.parse()?;
|
||||
Self::Let { name, ty, val }
|
||||
}
|
||||
_ => Self::Expr(ctx.parse()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FmtNode for Item {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result {
|
||||
match self {
|
||||
Item::Let { name, ty, val } => {
|
||||
write!(f, "let {}", name.dsp(ctx))?;
|
||||
if let Some(ty) = ty {
|
||||
write!(f, ": {}", ty.dsp(ctx))?;
|
||||
}
|
||||
write!(f, " = {}", val.dsp(ctx))?;
|
||||
}
|
||||
Item::Expr(id) => id.fmt(f, ctx)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Id<Item> {
|
||||
pub fn ends_with_block(&self, nodes: &Nodes) -> bool {
|
||||
match nodes[self] {
|
||||
Item::Let { name, ty, val } => val.ends_with_block(nodes),
|
||||
Item::Expr(id) => id.ends_with_block(nodes),
|
||||
}
|
||||
}
|
||||
pub fn needs_semicolon(&self, nodes: &Nodes) -> bool {
|
||||
!self.ends_with_block(nodes)
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,17 @@ mod body;
|
||||
mod expr;
|
||||
mod func;
|
||||
mod ident;
|
||||
mod item;
|
||||
mod param;
|
||||
mod struct_;
|
||||
mod ty;
|
||||
pub use body::*;
|
||||
pub use expr::*;
|
||||
pub use func::*;
|
||||
pub use ident::*;
|
||||
pub use item::*;
|
||||
pub use param::*;
|
||||
pub use struct_::*;
|
||||
pub use ty::*;
|
||||
|
||||
use super::{DisplayCtx, FmtNode, Id, Lit, Node, NodeVec, Parsable, ParseCtx, Token};
|
||||
@@ -22,6 +26,8 @@ def_nodes! {
|
||||
types: Type,
|
||||
funcs: Func,
|
||||
params: Param,
|
||||
items: Item,
|
||||
structs: Struct,
|
||||
}
|
||||
|
||||
macro_rules! def_nodes {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
use super::*;
|
||||
|
||||
pub struct Struct {
|
||||
name: String,
|
||||
fields: Vec<Field>,
|
||||
}
|
||||
|
||||
impl Parsable for Struct {
|
||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Field {
|
||||
}
|
||||
+6
-2
@@ -1,7 +1,11 @@
|
||||
x :i32 = 3;
|
||||
let x: i32 = 3;
|
||||
while true {
|
||||
print("hello");
|
||||
print(x);
|
||||
};
|
||||
|
||||
y := fn(x: i32) -> i32 {x};
|
||||
if x {
|
||||
print("hello");
|
||||
}
|
||||
|
||||
let y = fn(x: i32) -> i32 {x};
|
||||
|
||||
Reference in New Issue
Block a user