steal from jai
This commit is contained in:
@@ -64,12 +64,12 @@ impl<'a> Cursor<'a> {
|
||||
if next == *token {
|
||||
Ok(next)
|
||||
} else {
|
||||
self.unexpected(&next, &format!("'{token}'"))
|
||||
self.unexpected(next, &format!("'{token}'"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unexpected<T>(&self, token: &Token, expected: &str) -> Result<T, CompilerMsg> {
|
||||
Err(CompilerMsg::unexpected_token(token, self.span, expected))
|
||||
pub fn unexpected<T>(&self, token: Token, expected: &str) -> Result<T, CompilerMsg> {
|
||||
Err(CompilerMsg::unexpected_token(&token, self.span, expected))
|
||||
}
|
||||
|
||||
pub fn peek_start(&mut self) -> usize {
|
||||
|
||||
@@ -26,7 +26,6 @@ def_tokens! {
|
||||
DashEqual: "-=",
|
||||
AsteriskEqual: "*=",
|
||||
SlashEqual: "/=",
|
||||
DoubleColon: "::",
|
||||
Hash: "#",
|
||||
}
|
||||
keyword {
|
||||
@@ -38,6 +37,7 @@ def_tokens! {
|
||||
While: "while",
|
||||
For: "for",
|
||||
Match: "match",
|
||||
Break: "break",
|
||||
}
|
||||
other {
|
||||
Ident(String),
|
||||
@@ -112,10 +112,7 @@ impl Iterator for Tokens<'_> {
|
||||
_ => Token::Slash,
|
||||
'=' => Token::SlashEqual,
|
||||
},
|
||||
':' => then! {
|
||||
_ => Token::Colon,
|
||||
':' => Token::DoubleColon,
|
||||
},
|
||||
':' => Token::Colon,
|
||||
';' => Token::Semicolon,
|
||||
'=' => then! {
|
||||
_ => Token::Equal,
|
||||
|
||||
+7
-4
@@ -2,22 +2,25 @@ mod cursor;
|
||||
mod node;
|
||||
mod nodes;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use cursor::*;
|
||||
pub use node::*;
|
||||
pub use nodes::*;
|
||||
|
||||
use crate::io::CompilerOutput;
|
||||
|
||||
pub fn parse_file(path: &str, output: &mut CompilerOutput) -> Option<Body> {
|
||||
let code = match std::fs::read_to_string(path) {
|
||||
pub fn parse_file(path: impl AsRef<Path>, output: &mut CompilerOutput) -> Option<Body> {
|
||||
let code = match std::fs::read_to_string(&path) {
|
||||
Ok(code) => code,
|
||||
Err(err) => {
|
||||
output.error(format!("Failed to read input file: {err}"));
|
||||
return None;
|
||||
}
|
||||
};
|
||||
output.files.push(path.to_string());
|
||||
let mut ctx = ParseCtx::new(Cursor::new(&code, 0));
|
||||
let file = output.files.len();
|
||||
output.files.push(path.as_ref().to_path_buf());
|
||||
let mut ctx = ParseCtx::new(Cursor::new(&code, file));
|
||||
let root = match ctx.parse() {
|
||||
Ok(v) => v,
|
||||
Err(msg) => {
|
||||
|
||||
@@ -30,7 +30,7 @@ impl<'a> ParseCtx<'a> {
|
||||
) -> Result<N, CompilerMsg> {
|
||||
let old_start = self.start;
|
||||
self.start = self.cursor.peek_start();
|
||||
let res = f(self).map(|r| r);
|
||||
let res = f(self);
|
||||
self.start = old_start;
|
||||
res
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
|
||||
pub struct Body {
|
||||
pub items: Vec<Item>,
|
||||
pub items: Vec<Expr>,
|
||||
pub final_semicolon: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
@@ -16,9 +16,9 @@ impl Node for Body {
|
||||
if at_end(ctx) {
|
||||
break true;
|
||||
}
|
||||
let item: Item = ctx.parse()?;
|
||||
let needs_semicolon = item.needs_semicolon();
|
||||
items.push(item);
|
||||
let expr: Expr = ctx.parse()?;
|
||||
let needs_semicolon = expr.needs_semicolon();
|
||||
items.push(expr);
|
||||
if at_end(ctx) {
|
||||
break false;
|
||||
}
|
||||
|
||||
@@ -3,22 +3,48 @@ use crate::parser::VecDspT;
|
||||
pub use super::*;
|
||||
|
||||
pub struct Expr {
|
||||
span: Span,
|
||||
ty: ExprTy,
|
||||
pub span: Span,
|
||||
pub ty: ExprTy,
|
||||
}
|
||||
|
||||
pub enum ExprTy {
|
||||
Block(Body),
|
||||
Group(Box<Expr>),
|
||||
Member {
|
||||
of: Box<Expr>,
|
||||
field: Ident,
|
||||
},
|
||||
Ident(Ident),
|
||||
Lit(Lit),
|
||||
Negate(Box<Expr>),
|
||||
Call { target: Box<Expr>, args: Vec<Expr> },
|
||||
Assign { target: Box<Expr>, val: Box<Expr> },
|
||||
If { cond: Box<Expr>, body: Box<Expr> },
|
||||
Loop { body: Box<Expr> },
|
||||
While { cond: Box<Expr>, body: Box<Expr> },
|
||||
Call {
|
||||
target: Box<Expr>,
|
||||
args: Vec<Expr>,
|
||||
},
|
||||
Assign {
|
||||
target: Box<Expr>,
|
||||
val: Box<Expr>,
|
||||
},
|
||||
Define {
|
||||
target: Box<Expr>,
|
||||
ty: Option<Type>,
|
||||
const_: bool,
|
||||
val: Box<Expr>,
|
||||
},
|
||||
If {
|
||||
cond: Box<Expr>,
|
||||
body: Box<Expr>,
|
||||
},
|
||||
Loop {
|
||||
body: Box<Expr>,
|
||||
},
|
||||
While {
|
||||
cond: Box<Expr>,
|
||||
body: Box<Expr>,
|
||||
},
|
||||
Import(Ident),
|
||||
Fn(Box<Func>),
|
||||
Break,
|
||||
}
|
||||
|
||||
impl Node for Expr {
|
||||
@@ -32,12 +58,39 @@ impl Node for Expr {
|
||||
let val = Box::new(ctx.parse_with(Self::unit)?);
|
||||
ExprTy::Assign { target, val }
|
||||
}
|
||||
Token::Colon => {
|
||||
ctx.next();
|
||||
let target = Box::new(res);
|
||||
let mut ty = None;
|
||||
let next = ctx.expect_peek()?;
|
||||
if !matches!(next, Token::Equal | Token::Colon) {
|
||||
ty = Some(ctx.parse()?);
|
||||
}
|
||||
let const_ = match ctx.expect_next()? {
|
||||
Token::Equal => false,
|
||||
Token::Colon => true,
|
||||
t => ctx.unexpected(t, "an equals = or colon :")?,
|
||||
};
|
||||
let val = Box::new(ctx.parse_with(Self::unit)?);
|
||||
ExprTy::Define {
|
||||
target,
|
||||
ty,
|
||||
val,
|
||||
const_,
|
||||
}
|
||||
}
|
||||
Token::OpenParen => {
|
||||
ctx.next();
|
||||
let target = Box::new(res);
|
||||
let args = ctx.list(Token::Comma, Token::CloseParen)?;
|
||||
ExprTy::Call { target, args }
|
||||
}
|
||||
Token::Dot => {
|
||||
ctx.next();
|
||||
let of = Box::new(res);
|
||||
let field = ctx.parse()?;
|
||||
ExprTy::Member { of, field }
|
||||
}
|
||||
_ => break,
|
||||
};
|
||||
res = Self {
|
||||
@@ -69,6 +122,21 @@ impl ExprTy {
|
||||
Self::Assign { target, val } => {
|
||||
write!(f, "{} = {}", target.dsp(ctx), val.dsp(ctx))
|
||||
}
|
||||
Self::Define {
|
||||
target,
|
||||
ty,
|
||||
val,
|
||||
const_,
|
||||
} => {
|
||||
write!(f, "{} :", target.dsp(ctx))?;
|
||||
if let Some(ty) = ty {
|
||||
write!(f, " {} ", ty.dsp(ctx))?;
|
||||
}
|
||||
write!(f, "{} {}", if *const_ { ":" } else { "=" }, val.dsp(ctx))
|
||||
}
|
||||
Self::Member { of, field } => {
|
||||
write!(f, "{}.{field}", of.dsp(ctx))
|
||||
}
|
||||
Self::If { cond, body } => {
|
||||
write!(f, "if {} {}", cond.dsp(ctx), body.dsp(ctx))
|
||||
}
|
||||
@@ -88,6 +156,12 @@ impl ExprTy {
|
||||
write!(f, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
Self::Import(ident) => {
|
||||
write!(f, "import {ident}")
|
||||
}
|
||||
Self::Break => {
|
||||
write!(f, "break")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,7 +211,12 @@ impl Expr {
|
||||
ctx.expect(Token::CloseCurly)?;
|
||||
ExprTy::Block(body)
|
||||
}
|
||||
other => return ctx.unexpected(&other, "an expression"),
|
||||
Token::Break => ExprTy::Break,
|
||||
Token::Import => {
|
||||
let ident = ctx.parse()?;
|
||||
ExprTy::Import(ident)
|
||||
}
|
||||
other => return ctx.unexpected(other, "an expression"),
|
||||
};
|
||||
Ok(Self {
|
||||
ty,
|
||||
@@ -179,8 +258,13 @@ impl Expr {
|
||||
| ExprTy::If { body, .. }
|
||||
| ExprTy::Negate(body)
|
||||
| ExprTy::Assign { val: body, .. } => body.ends_with_block(),
|
||||
| ExprTy::Define { val: body, .. } => body.ends_with_block(),
|
||||
ExprTy::Fn(f) => f.ends_with_block(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn needs_semicolon(&self) -> bool {
|
||||
!self.ends_with_block()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ use super::*;
|
||||
|
||||
pub struct Func {
|
||||
args: Vec<Param>,
|
||||
name: Option<Ident>,
|
||||
ret: Option<Type>,
|
||||
body: Expr,
|
||||
span: Span,
|
||||
@@ -10,14 +9,6 @@ pub struct Func {
|
||||
|
||||
impl Node for Func {
|
||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
||||
let mut name = None;
|
||||
if let Token::Ident(ident) = ctx.expect_peek()? {
|
||||
// yucky
|
||||
let ident = ident.to_string();
|
||||
ctx.next();
|
||||
let ident = ctx.ident(ident);
|
||||
name = Some(ident);
|
||||
}
|
||||
ctx.expect(Token::OpenParen)?;
|
||||
let args = ctx.list(Token::Comma, Token::CloseParen)?;
|
||||
let mut ret = None;
|
||||
@@ -29,16 +20,12 @@ impl Node for Func {
|
||||
args,
|
||||
ret,
|
||||
body,
|
||||
name,
|
||||
span: ctx.span(),
|
||||
})
|
||||
}
|
||||
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter, ctx: DisplayCtx) -> std::fmt::Result {
|
||||
write!(f, "fn")?;
|
||||
if let Some(name) = &self.name {
|
||||
write!(f, " {name}")?;
|
||||
}
|
||||
write!(f, "(")?;
|
||||
if let Some((last, rest)) = self.args.split_last() {
|
||||
for arg in rest {
|
||||
|
||||
@@ -9,7 +9,7 @@ impl Node for Ident {
|
||||
fn parse(ctx: &mut super::ParseCtx) -> Result<Self, crate::io::CompilerMsg> {
|
||||
match ctx.expect_next()? {
|
||||
Token::Ident(ident) => Ok(ctx.ident(ident)),
|
||||
t => ctx.unexpected(&t, "an identifier"),
|
||||
t => ctx.unexpected(t, "an identifier"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ mod body;
|
||||
mod expr;
|
||||
mod func;
|
||||
mod ident;
|
||||
mod item;
|
||||
mod param;
|
||||
mod struct_;
|
||||
mod ty;
|
||||
@@ -10,7 +9,6 @@ pub use body::*;
|
||||
pub use expr::*;
|
||||
pub use func::*;
|
||||
pub use ident::*;
|
||||
pub use item::*;
|
||||
pub use param::*;
|
||||
pub use ty::*;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ impl Node for Type {
|
||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
||||
Ok(match ctx.expect_next()? {
|
||||
Token::Ident(s) => Self::Ident(ctx.ident(s)),
|
||||
t => ctx.unexpected(&t, "a type")?,
|
||||
t => ctx.unexpected(t, "a type")?,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user