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