stuff
This commit is contained in:
+106
@@ -0,0 +1,106 @@
|
|||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Span {
|
||||||
|
pub file: usize,
|
||||||
|
pub start: usize,
|
||||||
|
pub end: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Spanned<T> {
|
||||||
|
pub inner: T,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::Deref for Spanned<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::DerefMut for Spanned<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CompilerMsg {
|
||||||
|
pub spans: Vec<Span>,
|
||||||
|
pub msg: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct CompilerOutput {
|
||||||
|
pub errors: Vec<CompilerMsg>,
|
||||||
|
pub files: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompilerOutput {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
pub fn error(&mut self, msg: impl Into<CompilerMsg>) {
|
||||||
|
self.errors.push(msg.into());
|
||||||
|
}
|
||||||
|
pub fn write(&self, w: &mut impl std::io::Write) {
|
||||||
|
let files: Vec<_> = self
|
||||||
|
.files
|
||||||
|
.iter()
|
||||||
|
.map(|path| std::fs::read_to_string(path).unwrap())
|
||||||
|
.collect();
|
||||||
|
for error in &self.errors {
|
||||||
|
writeln!(w, "Error: {}", error.msg).unwrap();
|
||||||
|
for span in &error.spans {
|
||||||
|
span.write(w, &files[span.file]).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Span {
|
||||||
|
pub fn write(&self, w: &mut impl std::io::Write, text: &str) -> std::io::Result<()> {
|
||||||
|
let mut line_start = 0;
|
||||||
|
let mut found = false;
|
||||||
|
let mut line = 1;
|
||||||
|
let mut spans = Vec::new();
|
||||||
|
for (i, c) in text.char_indices() {
|
||||||
|
if i == self.start {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if i == self.end {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
if c == '\n' {
|
||||||
|
if found {
|
||||||
|
spans.push((line, line_start..i));
|
||||||
|
}
|
||||||
|
line_start = i + 1;
|
||||||
|
line += 1;
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let start_chars = text[self.start..].lines().next().unwrap().len();
|
||||||
|
let underline = "\x1b[4:3m";
|
||||||
|
let underline_color = "\x1b[58;5;1m";
|
||||||
|
let end = "\x1b[0m";
|
||||||
|
if let [(line, range)] = &spans[..] {
|
||||||
|
writeln!(
|
||||||
|
w,
|
||||||
|
" {line:3} | {}{underline}{underline_color}{}{end}{}",
|
||||||
|
&text[range.start..self.start],
|
||||||
|
&text[self.start..=self.end],
|
||||||
|
&text[(self.end + 1)..range.end]
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for CompilerMsg {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self {
|
||||||
|
spans: Vec::new(),
|
||||||
|
msg: value.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-7
@@ -1,3 +1,6 @@
|
|||||||
|
use crate::{io::CompilerOutput, parser::Nodes};
|
||||||
|
|
||||||
|
mod io;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -6,12 +9,11 @@ fn main() {
|
|||||||
println!("file expected");
|
println!("file expected");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let code = match std::fs::read_to_string(path) {
|
let mut output = CompilerOutput::new();
|
||||||
Ok(code) => code,
|
let nodes = Nodes::parse_root(&path, &mut output);
|
||||||
Err(err) => {
|
if let Some((nodes, root)) = nodes {
|
||||||
println!("Failed to read input file: {err}");
|
nodes.format(&mut std::io::stdout(), root).unwrap();
|
||||||
return;
|
println!();
|
||||||
}
|
}
|
||||||
};
|
output.write(&mut std::io::stdout());
|
||||||
parser::parse(&code);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-16
@@ -1,9 +1,7 @@
|
|||||||
use crate::parser::error::ParseError;
|
use crate::io::{CompilerMsg, Span, Spanned};
|
||||||
pub use span::*;
|
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
pub use token::*;
|
pub use token::*;
|
||||||
|
|
||||||
mod span;
|
|
||||||
mod token;
|
mod token;
|
||||||
|
|
||||||
pub struct Cursor<'a> {
|
pub struct Cursor<'a> {
|
||||||
@@ -12,10 +10,14 @@ pub struct Cursor<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Cursor<'a> {
|
impl<'a> Cursor<'a> {
|
||||||
pub fn new(text: &'a str) -> Self {
|
pub fn new(text: &'a str, file: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
span: Span { first: 0, last: 0 },
|
span: Span {
|
||||||
tokens: Tokens::new(text).peekable(),
|
start: 0,
|
||||||
|
end: 0,
|
||||||
|
file,
|
||||||
|
},
|
||||||
|
tokens: Tokens::new(text, file).peekable(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,14 +32,14 @@ impl<'a> Cursor<'a> {
|
|||||||
self.tokens.peek().map(|inst| &inst.inner)
|
self.tokens.peek().map(|inst| &inst.inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_next(&mut self) -> Result<Token, ParseError> {
|
pub fn expect_next(&mut self) -> Result<Token, CompilerMsg> {
|
||||||
self.next().ok_or_else(|| ParseError {
|
self.next().ok_or_else(|| CompilerMsg {
|
||||||
spans: Vec::new(),
|
spans: Vec::new(),
|
||||||
msg: "unexpected end of file".to_string(),
|
msg: "unexpected end of file".to_string(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect(&mut self, token: Token) -> Result<Token, ParseError> {
|
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 {
|
||||||
Ok(next)
|
Ok(next)
|
||||||
@@ -46,7 +48,7 @@ impl<'a> Cursor<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_ident(&mut self) -> Result<String, ParseError> {
|
pub fn expect_ident(&mut self) -> Result<String, CompilerMsg> {
|
||||||
let next = self.expect_next()?;
|
let next = self.expect_next()?;
|
||||||
if let Token::Ident(s) = next {
|
if let Token::Ident(s) = next {
|
||||||
Ok(s)
|
Ok(s)
|
||||||
@@ -55,8 +57,8 @@ impl<'a> Cursor<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unexpected<T>(&self, token: Token, expected: &str) -> Result<T, ParseError> {
|
pub fn unexpected<T>(&self, token: Token, expected: &str) -> Result<T, CompilerMsg> {
|
||||||
Err(ParseError::unexpected_token(
|
Err(CompilerMsg::unexpected_token(
|
||||||
Spanned {
|
Spanned {
|
||||||
inner: token,
|
inner: token,
|
||||||
span: self.span,
|
span: self.span,
|
||||||
@@ -65,11 +67,24 @@ impl<'a> Cursor<'a> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek_first(&mut self) -> usize {
|
pub fn peek_start(&mut self) -> usize {
|
||||||
self.tokens.peek().map(|i| i.span.first).unwrap_or(0)
|
self.tokens.peek().map(|i| i.span.start).unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cur_last(&mut self) -> usize {
|
pub fn cur_end(&mut self) -> usize {
|
||||||
self.span.last
|
self.span.end
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file(&mut self) -> usize {
|
||||||
|
self.span.file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompilerMsg {
|
||||||
|
pub fn unexpected_token(inst: TokenInst, expected: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
spans: vec![inst.span],
|
||||||
|
msg: format!("Unexpected token '{}'; expected {expected}", inst.inner),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct Span {
|
|
||||||
pub first: usize,
|
|
||||||
pub last: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Spanned<T> {
|
|
||||||
pub inner: T,
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> std::ops::Deref for Spanned<T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> std::ops::DerefMut for Spanned<T> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -39,12 +39,14 @@ impl From<Lit> for Token {
|
|||||||
pub type TokenInst = Spanned<Token>;
|
pub type TokenInst = Spanned<Token>;
|
||||||
|
|
||||||
pub struct Tokens<'a> {
|
pub struct Tokens<'a> {
|
||||||
|
file: usize,
|
||||||
text: Peekable<CharIndices<'a>>,
|
text: Peekable<CharIndices<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Tokens<'a> {
|
impl<'a> Tokens<'a> {
|
||||||
pub fn new(code: &'a str) -> Self {
|
pub fn new(code: &'a str, file: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
file,
|
||||||
text: code.char_indices().peekable(),
|
text: code.char_indices().peekable(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +57,11 @@ impl Iterator for Tokens<'_> {
|
|||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let (i, c) = self.text.next()?;
|
let (i, c) = self.text.next()?;
|
||||||
let mut span = Span { first: i, last: i };
|
let mut span = Span {
|
||||||
|
start: i,
|
||||||
|
end: i,
|
||||||
|
file: self.file,
|
||||||
|
};
|
||||||
Some(Spanned {
|
Some(Spanned {
|
||||||
inner: match c {
|
inner: match c {
|
||||||
'=' => Token::Equal,
|
'=' => Token::Equal,
|
||||||
@@ -78,7 +84,7 @@ impl Iterator for Tokens<'_> {
|
|||||||
&& c.is_alphanumeric()
|
&& c.is_alphanumeric()
|
||||||
{
|
{
|
||||||
s.push(*c);
|
s.push(*c);
|
||||||
span.last = *i;
|
span.end = *i;
|
||||||
self.text.next();
|
self.text.next();
|
||||||
}
|
}
|
||||||
Lit::Number(s).into()
|
Lit::Number(s).into()
|
||||||
@@ -89,7 +95,7 @@ impl Iterator for Tokens<'_> {
|
|||||||
&& !matches!(c, '"')
|
&& !matches!(c, '"')
|
||||||
{
|
{
|
||||||
s.push(*c);
|
s.push(*c);
|
||||||
span.last = *i;
|
span.end = *i;
|
||||||
self.text.next();
|
self.text.next();
|
||||||
}
|
}
|
||||||
self.text.next();
|
self.text.next();
|
||||||
@@ -104,7 +110,7 @@ impl Iterator for Tokens<'_> {
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
s.push(*c);
|
s.push(*c);
|
||||||
span.last = *i;
|
span.end = *i;
|
||||||
self.text.next();
|
self.text.next();
|
||||||
}
|
}
|
||||||
match s.as_str() {
|
match s.as_str() {
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
use crate::parser::cursor::{Span, TokenInst};
|
|
||||||
|
|
||||||
pub struct ParseError {
|
|
||||||
pub spans: Vec<Span>,
|
|
||||||
pub msg: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParseError {
|
|
||||||
pub fn unexpected_token(inst: TokenInst, expected: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
spans: vec![inst.span],
|
|
||||||
msg: format!("Unexpected token {}; expected {expected}", inst.inner),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
mod cursor;
|
mod cursor;
|
||||||
mod error;
|
|
||||||
mod node;
|
mod node;
|
||||||
|
|
||||||
pub fn parse(code: &str) {}
|
pub use node::*;
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use crate::parser::{
|
|
||||||
cursor::{Cursor, Span, Token},
|
|
||||||
error::ParseError,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait Parsable: Sized {
|
|
||||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, ParseError>;
|
|
||||||
fn vec(nodes: &mut Nodes) -> &mut NodeVec<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ParseCtx<'a> {
|
|
||||||
cursor: Cursor<'a>,
|
|
||||||
nodes: Nodes,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Nodes {
|
|
||||||
statements: NodeVec<Statement>,
|
|
||||||
exprs: NodeVec<Expr>,
|
|
||||||
idents: NodeVec<Ident>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NodeVec<N> {
|
|
||||||
vec: Vec<N>,
|
|
||||||
spans: Vec<Span>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N> NodeVec<N> {
|
|
||||||
pub fn add(&mut self, v: N, span: Span) -> Id<N> {
|
|
||||||
let id = self.vec.len();
|
|
||||||
self.vec.push(v);
|
|
||||||
self.spans.push(span);
|
|
||||||
Id {
|
|
||||||
id,
|
|
||||||
_pd: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Statement {
|
|
||||||
Let(Id<Ident>, Id<Expr>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Expr {
|
|
||||||
Ident(Id<Ident>),
|
|
||||||
Negate(Id<Expr>),
|
|
||||||
Assign(Id<Expr>, Id<Expr>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Id<T> {
|
|
||||||
id: usize,
|
|
||||||
_pd: PhantomData<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Ident {
|
|
||||||
inner: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parsable for Expr {
|
|
||||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, ParseError> {
|
|
||||||
Ok(match ctx.cursor.expect_next()? {
|
|
||||||
Token::Dash => Self::Negate(ctx.parse()?),
|
|
||||||
Token::Ident(s) => Self::Ident(ctx.ident(s)),
|
|
||||||
other => return ctx.cursor.unexpected(other, "an expression"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vec(nodes: &mut Nodes) -> &mut NodeVec<Self> {
|
|
||||||
&mut nodes.exprs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParseCtx<'_> {
|
|
||||||
pub fn parse<P: Parsable>(&mut self) -> Result<Id<P>, ParseError> {
|
|
||||||
let first = self.cursor.peek_first();
|
|
||||||
P::parse(self).map(|r| {
|
|
||||||
let last = self.cursor.cur_last();
|
|
||||||
P::vec(&mut self.nodes).add(r, Span { first, last })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ident(&mut self, s: String) -> Id<Ident> {
|
|
||||||
let span = self.cursor.span;
|
|
||||||
self.nodes.idents.add(Ident { inner: s }, span)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
use crate::{
|
||||||
|
io::CompilerMsg,
|
||||||
|
parser::{
|
||||||
|
cursor::{Lit, Token},
|
||||||
|
*,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum Statement {
|
||||||
|
Let(Id<Ident>, Id<Expr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Expr {
|
||||||
|
Ident(Id<Ident>),
|
||||||
|
Lit(Id<Lit>),
|
||||||
|
Negate(Id<Expr>),
|
||||||
|
Assign(Id<Expr>, Id<Expr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Ident {
|
||||||
|
pub inner: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FmtNode for Ident {
|
||||||
|
fn format(&self, w: &mut impl std::io::Write, _: &Nodes) -> std::io::Result<()> {
|
||||||
|
write!(w, "{}", self.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parsable for Expr {
|
||||||
|
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
||||||
|
let e1 = match ctx.cursor.expect_next()? {
|
||||||
|
Token::Dash => Self::Negate(ctx.parse()?),
|
||||||
|
Token::Ident(s) => Self::Ident(ctx.ident(s)),
|
||||||
|
Token::Lit(l) => Self::Lit(ctx.lit(l)),
|
||||||
|
other => return ctx.cursor.unexpected(other, "an expression"),
|
||||||
|
};
|
||||||
|
let Some(next) = ctx.cursor.peek() else {
|
||||||
|
return Ok(e1);
|
||||||
|
};
|
||||||
|
Ok(match next {
|
||||||
|
Token::Equal => {
|
||||||
|
let e1 = ctx.push_adv(e1);
|
||||||
|
let e2: Id<Expr> = ctx.parse()?;
|
||||||
|
Expr::Assign(e1, e2)
|
||||||
|
}
|
||||||
|
_ => e1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FmtNode for Expr {
|
||||||
|
fn format(&self, w: &mut impl std::io::Write, nodes: &Nodes) -> std::io::Result<()> {
|
||||||
|
match *self {
|
||||||
|
Expr::Ident(id) => nodes.format(w, id),
|
||||||
|
Expr::Lit(id) => nodes.format(w, id),
|
||||||
|
Expr::Negate(id) => {
|
||||||
|
write!(w, "-")?;
|
||||||
|
nodes.format(w, id)
|
||||||
|
}
|
||||||
|
Expr::Assign(id1, id2) => {
|
||||||
|
nodes.format(w, id1)?;
|
||||||
|
write!(w, " = ")?;
|
||||||
|
nodes.format(w, id2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FmtNode for Lit {
|
||||||
|
fn format(&self, w: &mut impl std::io::Write, _: &Nodes) -> std::io::Result<()> {
|
||||||
|
match self {
|
||||||
|
Lit::Number(v) => write!(w, "{v}"),
|
||||||
|
Lit::Bool(v) => write!(w, "{v}"),
|
||||||
|
Lit::String(v) => write!(w, "{v}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
use crate::{
|
||||||
|
io::{CompilerMsg, CompilerOutput, Span},
|
||||||
|
parser::cursor::{Cursor, Lit},
|
||||||
|
};
|
||||||
|
use std::{marker::PhantomData, ops::Index};
|
||||||
|
|
||||||
|
mod expr;
|
||||||
|
pub use expr::*;
|
||||||
|
|
||||||
|
pub trait Parsable: Sized + Node {
|
||||||
|
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParseCtx<'a> {
|
||||||
|
start: usize,
|
||||||
|
cursor: Cursor<'a>,
|
||||||
|
nodes: Nodes,
|
||||||
|
}
|
||||||
|
|
||||||
|
def_nodes!(
|
||||||
|
exprs: Expr,
|
||||||
|
idents: Ident,
|
||||||
|
statements: Statement,
|
||||||
|
lits: Lit,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl Nodes {
|
||||||
|
pub fn parse_root(path: &str, output: &mut CompilerOutput) -> Option<(Self, Id<Expr>)> {
|
||||||
|
let root_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 nodes = Self::default();
|
||||||
|
let mut ctx = ParseCtx {
|
||||||
|
start: 0,
|
||||||
|
nodes,
|
||||||
|
cursor: Cursor::new(&root_code, 0),
|
||||||
|
};
|
||||||
|
let root = match ctx.parse::<Expr>() {
|
||||||
|
Ok(expr) => expr,
|
||||||
|
Err(msg) => {
|
||||||
|
output.error(msg);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some((ctx.nodes, root))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format<N: FmtNode>(
|
||||||
|
&self,
|
||||||
|
w: &mut impl std::io::Write,
|
||||||
|
id: Id<N>,
|
||||||
|
) -> std::io::Result<()> {
|
||||||
|
self[id].format(w, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Node> Index<Id<N>> for Nodes {
|
||||||
|
type Output = N;
|
||||||
|
|
||||||
|
fn index(&self, index: Id<N>) -> &Self::Output {
|
||||||
|
&N::vec(self).vec[index.id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Node> Index<&Id<N>> for Nodes {
|
||||||
|
type Output = N;
|
||||||
|
|
||||||
|
fn index(&self, index: &Id<N>) -> &Self::Output {
|
||||||
|
&N::vec(self).vec[index.id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NodeVec<N> {
|
||||||
|
vec: Vec<N>,
|
||||||
|
spans: Vec<Span>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N> NodeVec<N> {
|
||||||
|
pub fn add(&mut self, v: N, span: Span) -> Id<N> {
|
||||||
|
let id = self.vec.len();
|
||||||
|
self.vec.push(v);
|
||||||
|
self.spans.push(span);
|
||||||
|
Id {
|
||||||
|
id,
|
||||||
|
_pd: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N> Default for NodeVec<N> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
vec: Default::default(),
|
||||||
|
spans: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Id<T> {
|
||||||
|
id: usize,
|
||||||
|
_pd: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for Id<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Copy for Id<T> {}
|
||||||
|
|
||||||
|
pub trait Node: Sized {
|
||||||
|
fn vec(nodes: &Nodes) -> &NodeVec<Self>;
|
||||||
|
fn vec_mut(nodes: &mut Nodes) -> &mut NodeVec<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParseCtx<'_> {
|
||||||
|
pub fn parse<P: Parsable>(&mut self) -> Result<Id<P>, CompilerMsg> {
|
||||||
|
let old_start = self.start;
|
||||||
|
self.start = self.cursor.peek_start();
|
||||||
|
let res = P::parse(self).map(|r| self.push(r));
|
||||||
|
self.start = old_start;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ident(&mut self, s: String) -> Id<Ident> {
|
||||||
|
let span = self.cursor.span;
|
||||||
|
self.nodes.idents.add(Ident { inner: s }, span)
|
||||||
|
}
|
||||||
|
pub fn lit(&mut self, lit: Lit) -> Id<Lit> {
|
||||||
|
let span = self.cursor.span;
|
||||||
|
self.nodes.lits.add(lit, span)
|
||||||
|
}
|
||||||
|
pub fn push_adv<N: Node>(&mut self, node: N) -> Id<N> {
|
||||||
|
let res = self.push(node);
|
||||||
|
self.cursor.next();
|
||||||
|
res
|
||||||
|
}
|
||||||
|
pub fn push<N: Node>(&mut self, node: N) -> Id<N> {
|
||||||
|
let end = self.cursor.cur_end();
|
||||||
|
N::vec_mut(&mut self.nodes).add(
|
||||||
|
node,
|
||||||
|
Span {
|
||||||
|
file: self.cursor.file(),
|
||||||
|
start: self.start,
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! def_nodes {
|
||||||
|
($($field:ident: $ty:ident,)*) => {
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Nodes {
|
||||||
|
$($field: NodeVec<$ty>,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
$(impl Node for $ty {
|
||||||
|
fn vec(nodes: &Nodes) -> &NodeVec<Self> {
|
||||||
|
&nodes.$field
|
||||||
|
}
|
||||||
|
fn vec_mut(nodes: &mut Nodes) -> &mut NodeVec<Self> {
|
||||||
|
&mut nodes.$field
|
||||||
|
}
|
||||||
|
})*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
use def_nodes;
|
||||||
|
|
||||||
|
pub trait FmtNode: Node {
|
||||||
|
fn format(&self, w: &mut impl std::io::Write, nodes: &Nodes) -> std::io::Result<()>;
|
||||||
|
}
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
let x = 3;
|
x =/ arst -3
|
||||||
|
|||||||
Reference in New Issue
Block a user