work
This commit is contained in:
@@ -0,0 +1,54 @@
|
|||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
pub struct Id<T> {
|
||||||
|
idx: usize,
|
||||||
|
_pd: std::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IdVec<T> {
|
||||||
|
vec: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IdVec<T> {
|
||||||
|
pub fn add(&mut self, val: T) -> Id<T> {
|
||||||
|
let id = Id {
|
||||||
|
idx: self.vec.len(),
|
||||||
|
_pd: Default::default(),
|
||||||
|
};
|
||||||
|
self.vec.push(val);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Index<Id<T>> for IdVec<T> {
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
fn index(&self, index: Id<T>) -> &Self::Output {
|
||||||
|
&self.vec[index.idx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IndexMut<Id<T>> for IdVec<T> {
|
||||||
|
fn index_mut(&mut self, index: Id<T>) -> &mut Self::Output {
|
||||||
|
&mut self.vec[index.idx]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for IdVec<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
vec: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for Id<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
idx: self.idx.clone(),
|
||||||
|
_pd: self._pd.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Copy for Id<T> {}
|
||||||
+20
-1
@@ -1,4 +1,23 @@
|
|||||||
|
mod id;
|
||||||
mod structs;
|
mod structs;
|
||||||
|
pub use id::*;
|
||||||
pub use structs::*;
|
pub use structs::*;
|
||||||
|
|
||||||
pub struct Ir {}
|
pub struct Ir {
|
||||||
|
pub root: Id<Namespace>,
|
||||||
|
pub namespaces: IdVec<Namespace>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ir {
|
||||||
|
pub fn root(&mut self) -> &mut Namespace {
|
||||||
|
&mut self.namespaces[self.root]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Ir {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut namespaces = IdVec::default();
|
||||||
|
let root = namespaces.add(Namespace::default());
|
||||||
|
Self { root, namespaces }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
pub struct Module {}
|
mod namespace;
|
||||||
|
pub use namespace::*;
|
||||||
|
|
||||||
|
use super::Id;
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::parser::Ident;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Namespace {
|
||||||
|
pub items: HashMap<Ident, Item>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Item {
|
||||||
|
Import(Id<Namespace>),
|
||||||
|
}
|
||||||
|
|
||||||
|
// issue: if I try to parse a function body, I'll want to have clear statements such as
|
||||||
|
// "call trait fn func on x" or "call field func of x", but you (often) can't tell until typed
|
||||||
|
// x.func
|
||||||
|
// x'func
|
||||||
+4
-8
@@ -1,11 +1,13 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
io::CompilerOutput,
|
io::CompilerOutput,
|
||||||
parser::{Node, parse_root},
|
parser::{Node, parse_file},
|
||||||
|
parser_ir::parse_program,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod io;
|
mod io;
|
||||||
mod ir;
|
mod ir;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
mod parser_ir;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
@@ -14,15 +16,9 @@ fn main() {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let mut output = CompilerOutput::new();
|
let mut output = CompilerOutput::new();
|
||||||
let root = parse_root(&path, &mut output);
|
let root = parse_file(&path, &mut output);
|
||||||
if let Some(root) = root {
|
if let Some(root) = root {
|
||||||
print!("{}", root.new_dsp());
|
print!("{}", root.new_dsp());
|
||||||
// for item in &root.items {
|
|
||||||
// output.errors.push(io::CompilerMsg {
|
|
||||||
// spans: vec![item.span],
|
|
||||||
// msg: format!("hello"),
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
output.write(&mut std::io::stdout());
|
output.write(&mut std::io::stdout());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ def_tokens! {
|
|||||||
}
|
}
|
||||||
keyword {
|
keyword {
|
||||||
Let: "let",
|
Let: "let",
|
||||||
Do: "do",
|
Import: "import",
|
||||||
Fn: "fn",
|
Fn: "fn",
|
||||||
If: "if",
|
If: "if",
|
||||||
Loop: "loop",
|
Loop: "loop",
|
||||||
|
|||||||
@@ -5,3 +5,25 @@ mod nodes;
|
|||||||
use cursor::*;
|
use cursor::*;
|
||||||
pub use node::*;
|
pub use node::*;
|
||||||
pub use nodes::*;
|
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) {
|
||||||
|
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 root = match ctx.parse() {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(msg) => {
|
||||||
|
output.error(msg);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(root)
|
||||||
|
}
|
||||||
|
|||||||
+2
-25
@@ -1,13 +1,10 @@
|
|||||||
use crate::{
|
|
||||||
io::{CompilerMsg, CompilerOutput},
|
|
||||||
parser::{Cursor, nodes::*},
|
|
||||||
};
|
|
||||||
|
|
||||||
mod ctx;
|
mod ctx;
|
||||||
mod dsp;
|
mod dsp;
|
||||||
pub use ctx::*;
|
pub use ctx::*;
|
||||||
pub use dsp::*;
|
pub use dsp::*;
|
||||||
|
|
||||||
|
use crate::io::CompilerMsg;
|
||||||
|
|
||||||
pub trait Node: Sized {
|
pub trait Node: Sized {
|
||||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg>;
|
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg>;
|
||||||
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;
|
||||||
@@ -18,23 +15,3 @@ pub trait Node: Sized {
|
|||||||
self.dsp(DisplayCtx { indent: 0 })
|
self.dsp(DisplayCtx { indent: 0 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_root(path: &str, output: &mut CompilerOutput) -> Option<Body> {
|
|
||||||
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 mut ctx = ParseCtx::new(Cursor::new(&root_code, 0));
|
|
||||||
let root = match ctx.parse() {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(msg) => {
|
|
||||||
output.error(msg);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(root)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,12 +11,18 @@ pub enum ItemTy {
|
|||||||
ty: Option<Type>,
|
ty: Option<Type>,
|
||||||
val: Expr,
|
val: Expr,
|
||||||
},
|
},
|
||||||
|
Fn(Func),
|
||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
|
Import(Ident),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for Item {
|
impl Node for Item {
|
||||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
||||||
let ty = match ctx.expect_peek()? {
|
let ty = match ctx.expect_peek()? {
|
||||||
|
Token::Fn => {
|
||||||
|
ctx.next();
|
||||||
|
ItemTy::Fn(ctx.parse()?)
|
||||||
|
}
|
||||||
Token::Let => {
|
Token::Let => {
|
||||||
ctx.next();
|
ctx.next();
|
||||||
let name = ctx.parse()?;
|
let name = ctx.parse()?;
|
||||||
@@ -28,6 +34,10 @@ impl Node for Item {
|
|||||||
let val = ctx.parse()?;
|
let val = ctx.parse()?;
|
||||||
ItemTy::Let { name, ty, val }
|
ItemTy::Let { name, ty, val }
|
||||||
}
|
}
|
||||||
|
Token::Import => {
|
||||||
|
ctx.next();
|
||||||
|
ItemTy::Import(ctx.parse()?)
|
||||||
|
}
|
||||||
_ => ItemTy::Expr(ctx.parse()?),
|
_ => ItemTy::Expr(ctx.parse()?),
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@@ -38,6 +48,7 @@ impl Node for Item {
|
|||||||
|
|
||||||
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 {
|
||||||
match &self.ty {
|
match &self.ty {
|
||||||
|
ItemTy::Fn(func) => func.fmt(f, ctx)?,
|
||||||
ItemTy::Let { name, ty, val } => {
|
ItemTy::Let { name, ty, val } => {
|
||||||
write!(f, "let {}", name.dsp(ctx))?;
|
write!(f, "let {}", name.dsp(ctx))?;
|
||||||
if let Some(ty) = ty {
|
if let Some(ty) = ty {
|
||||||
@@ -45,7 +56,8 @@ impl Node for Item {
|
|||||||
}
|
}
|
||||||
write!(f, " = {}", val.dsp(ctx))?;
|
write!(f, " = {}", val.dsp(ctx))?;
|
||||||
}
|
}
|
||||||
ItemTy::Expr(id) => id.fmt(f, ctx)?,
|
ItemTy::Expr(expr) => expr.fmt(f, ctx)?,
|
||||||
|
ItemTy::Import(ident) => write!(f, "import {}", ident.dsp(ctx))?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -56,6 +68,8 @@ impl Item {
|
|||||||
match &self.ty {
|
match &self.ty {
|
||||||
ItemTy::Let { val, .. } => val.ends_with_block(),
|
ItemTy::Let { val, .. } => val.ends_with_block(),
|
||||||
ItemTy::Expr(id) => id.ends_with_block(),
|
ItemTy::Expr(id) => id.ends_with_block(),
|
||||||
|
ItemTy::Fn(f) => f.ends_with_block(),
|
||||||
|
ItemTy::Import(ident) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn needs_semicolon(&self) -> bool {
|
pub fn needs_semicolon(&self) -> bool {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
use crate::{
|
||||||
|
io::CompilerOutput,
|
||||||
|
ir::{Ir, Namespace},
|
||||||
|
parser::{self, parse_file},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parse_program(path: &str, output: &mut CompilerOutput) -> Option<Ir> {
|
||||||
|
let root = parse_file(path, output)?;
|
||||||
|
let mut ir = Ir::default();
|
||||||
|
add_defs(ir.root(), &root);
|
||||||
|
Some(ir)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_defs(namespace: &mut Namespace, body: &parser::Body) {
|
||||||
|
for item in &body.items {
|
||||||
|
match &item.ty {
|
||||||
|
parser::ItemTy::Let { name, ty, val } => todo!(),
|
||||||
|
parser::ItemTy::Fn(func) => todo!(),
|
||||||
|
parser::ItemTy::Expr(expr) => todo!(),
|
||||||
|
parser::ItemTy::Import(ident) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -1,3 +1,5 @@
|
|||||||
|
modl other;
|
||||||
|
|
||||||
let x: i32 = 3;
|
let x: i32 = 3;
|
||||||
while true {
|
while true {
|
||||||
print("hello");
|
print("hello");
|
||||||
@@ -9,5 +11,4 @@ let y = true;
|
|||||||
if y => print("hello");
|
if y => print("hello");
|
||||||
|
|
||||||
fn thing() {
|
fn thing() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fn thing() {
|
||||||
|
print("hello from other");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user