steal from jai
This commit is contained in:
+14
-3
@@ -1,3 +1,5 @@
|
|||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Span {
|
pub struct Span {
|
||||||
pub file: usize,
|
pub file: usize,
|
||||||
@@ -32,7 +34,7 @@ pub struct CompilerMsg {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CompilerOutput {
|
pub struct CompilerOutput {
|
||||||
pub errors: Vec<CompilerMsg>,
|
pub errors: Vec<CompilerMsg>,
|
||||||
pub files: Vec<String>,
|
pub files: Vec<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilerOutput {
|
impl CompilerOutput {
|
||||||
@@ -112,10 +114,19 @@ impl Span {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for CompilerMsg {
|
impl From<String> for CompilerMsg {
|
||||||
fn from(value: String) -> Self {
|
fn from(msg: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
spans: Vec::new(),
|
spans: Vec::new(),
|
||||||
msg: value.to_string(),
|
msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Into<String>> From<(S, Span)> for CompilerMsg {
|
||||||
|
fn from((msg, span): (S, Span)) -> Self {
|
||||||
|
Self {
|
||||||
|
spans: vec![span],
|
||||||
|
msg: msg.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,6 @@ mod namespace;
|
|||||||
pub use namespace::*;
|
pub use namespace::*;
|
||||||
|
|
||||||
use super::Id;
|
use super::Id;
|
||||||
|
|
||||||
|
pub struct Fn {
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::parser::Ident;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Namespace {
|
pub struct Namespace {
|
||||||
pub items: HashMap<Ident, Item>,
|
pub items: HashMap<String, Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Item {
|
pub enum Item {
|
||||||
Import(Id<Namespace>),
|
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
|
|
||||||
|
|||||||
+2
-9
@@ -1,8 +1,4 @@
|
|||||||
use crate::{
|
use crate::{io::CompilerOutput, parser_ir::parse_program};
|
||||||
io::CompilerOutput,
|
|
||||||
parser::{Node, parse_file},
|
|
||||||
parser_ir::parse_program,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod io;
|
mod io;
|
||||||
mod ir;
|
mod ir;
|
||||||
@@ -16,9 +12,6 @@ fn main() {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let mut output = CompilerOutput::new();
|
let mut output = CompilerOutput::new();
|
||||||
let root = parse_file(&path, &mut output);
|
let ir = parse_program(&path, &mut output);
|
||||||
if let Some(root) = root {
|
|
||||||
print!("{}", root.new_dsp());
|
|
||||||
}
|
|
||||||
output.write(&mut std::io::stdout());
|
output.write(&mut std::io::stdout());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,12 +64,12 @@ impl<'a> Cursor<'a> {
|
|||||||
if next == *token {
|
if next == *token {
|
||||||
Ok(next)
|
Ok(next)
|
||||||
} else {
|
} else {
|
||||||
self.unexpected(&next, &format!("'{token}'"))
|
self.unexpected(next, &format!("'{token}'"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unexpected<T>(&self, token: &Token, expected: &str) -> Result<T, CompilerMsg> {
|
pub fn unexpected<T>(&self, token: Token, expected: &str) -> Result<T, CompilerMsg> {
|
||||||
Err(CompilerMsg::unexpected_token(token, self.span, expected))
|
Err(CompilerMsg::unexpected_token(&token, self.span, expected))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek_start(&mut self) -> usize {
|
pub fn peek_start(&mut self) -> usize {
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ def_tokens! {
|
|||||||
DashEqual: "-=",
|
DashEqual: "-=",
|
||||||
AsteriskEqual: "*=",
|
AsteriskEqual: "*=",
|
||||||
SlashEqual: "/=",
|
SlashEqual: "/=",
|
||||||
DoubleColon: "::",
|
|
||||||
Hash: "#",
|
Hash: "#",
|
||||||
}
|
}
|
||||||
keyword {
|
keyword {
|
||||||
@@ -38,6 +37,7 @@ def_tokens! {
|
|||||||
While: "while",
|
While: "while",
|
||||||
For: "for",
|
For: "for",
|
||||||
Match: "match",
|
Match: "match",
|
||||||
|
Break: "break",
|
||||||
}
|
}
|
||||||
other {
|
other {
|
||||||
Ident(String),
|
Ident(String),
|
||||||
@@ -112,10 +112,7 @@ impl Iterator for Tokens<'_> {
|
|||||||
_ => Token::Slash,
|
_ => Token::Slash,
|
||||||
'=' => Token::SlashEqual,
|
'=' => Token::SlashEqual,
|
||||||
},
|
},
|
||||||
':' => then! {
|
':' => Token::Colon,
|
||||||
_ => Token::Colon,
|
|
||||||
':' => Token::DoubleColon,
|
|
||||||
},
|
|
||||||
';' => Token::Semicolon,
|
';' => Token::Semicolon,
|
||||||
'=' => then! {
|
'=' => then! {
|
||||||
_ => Token::Equal,
|
_ => Token::Equal,
|
||||||
|
|||||||
+7
-4
@@ -2,22 +2,25 @@ mod cursor;
|
|||||||
mod node;
|
mod node;
|
||||||
mod nodes;
|
mod nodes;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use cursor::*;
|
use cursor::*;
|
||||||
pub use node::*;
|
pub use node::*;
|
||||||
pub use nodes::*;
|
pub use nodes::*;
|
||||||
|
|
||||||
use crate::io::CompilerOutput;
|
use crate::io::CompilerOutput;
|
||||||
|
|
||||||
pub fn parse_file(path: &str, output: &mut CompilerOutput) -> Option<Body> {
|
pub fn parse_file(path: impl AsRef<Path>, output: &mut CompilerOutput) -> Option<Body> {
|
||||||
let code = match std::fs::read_to_string(path) {
|
let code = match std::fs::read_to_string(&path) {
|
||||||
Ok(code) => code,
|
Ok(code) => code,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
output.error(format!("Failed to read input file: {err}"));
|
output.error(format!("Failed to read input file: {err}"));
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
output.files.push(path.to_string());
|
let file = output.files.len();
|
||||||
let mut ctx = ParseCtx::new(Cursor::new(&code, 0));
|
output.files.push(path.as_ref().to_path_buf());
|
||||||
|
let mut ctx = ParseCtx::new(Cursor::new(&code, file));
|
||||||
let root = match ctx.parse() {
|
let root = match ctx.parse() {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(msg) => {
|
Err(msg) => {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ impl<'a> ParseCtx<'a> {
|
|||||||
) -> Result<N, CompilerMsg> {
|
) -> Result<N, CompilerMsg> {
|
||||||
let old_start = self.start;
|
let old_start = self.start;
|
||||||
self.start = self.cursor.peek_start();
|
self.start = self.cursor.peek_start();
|
||||||
let res = f(self).map(|r| r);
|
let res = f(self);
|
||||||
self.start = old_start;
|
self.start = old_start;
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
pub items: Vec<Item>,
|
pub items: Vec<Expr>,
|
||||||
pub final_semicolon: bool,
|
pub final_semicolon: bool,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
@@ -16,9 +16,9 @@ impl Node for Body {
|
|||||||
if at_end(ctx) {
|
if at_end(ctx) {
|
||||||
break true;
|
break true;
|
||||||
}
|
}
|
||||||
let item: Item = ctx.parse()?;
|
let expr: Expr = ctx.parse()?;
|
||||||
let needs_semicolon = item.needs_semicolon();
|
let needs_semicolon = expr.needs_semicolon();
|
||||||
items.push(item);
|
items.push(expr);
|
||||||
if at_end(ctx) {
|
if at_end(ctx) {
|
||||||
break false;
|
break false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,22 +3,48 @@ use crate::parser::VecDspT;
|
|||||||
pub use super::*;
|
pub use super::*;
|
||||||
|
|
||||||
pub struct Expr {
|
pub struct Expr {
|
||||||
span: Span,
|
pub span: Span,
|
||||||
ty: ExprTy,
|
pub ty: ExprTy,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ExprTy {
|
pub enum ExprTy {
|
||||||
Block(Body),
|
Block(Body),
|
||||||
Group(Box<Expr>),
|
Group(Box<Expr>),
|
||||||
|
Member {
|
||||||
|
of: Box<Expr>,
|
||||||
|
field: Ident,
|
||||||
|
},
|
||||||
Ident(Ident),
|
Ident(Ident),
|
||||||
Lit(Lit),
|
Lit(Lit),
|
||||||
Negate(Box<Expr>),
|
Negate(Box<Expr>),
|
||||||
Call { target: Box<Expr>, args: Vec<Expr> },
|
Call {
|
||||||
Assign { target: Box<Expr>, val: Box<Expr> },
|
target: Box<Expr>,
|
||||||
If { cond: Box<Expr>, body: Box<Expr> },
|
args: Vec<Expr>,
|
||||||
Loop { body: Box<Expr> },
|
},
|
||||||
While { cond: Box<Expr>, body: Box<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>),
|
Fn(Box<Func>),
|
||||||
|
Break,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for Expr {
|
impl Node for Expr {
|
||||||
@@ -32,12 +58,39 @@ impl Node for Expr {
|
|||||||
let val = Box::new(ctx.parse_with(Self::unit)?);
|
let val = Box::new(ctx.parse_with(Self::unit)?);
|
||||||
ExprTy::Assign { target, val }
|
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 => {
|
Token::OpenParen => {
|
||||||
ctx.next();
|
ctx.next();
|
||||||
let target = Box::new(res);
|
let target = Box::new(res);
|
||||||
let args = ctx.list(Token::Comma, Token::CloseParen)?;
|
let args = ctx.list(Token::Comma, Token::CloseParen)?;
|
||||||
ExprTy::Call { target, args }
|
ExprTy::Call { target, args }
|
||||||
}
|
}
|
||||||
|
Token::Dot => {
|
||||||
|
ctx.next();
|
||||||
|
let of = Box::new(res);
|
||||||
|
let field = ctx.parse()?;
|
||||||
|
ExprTy::Member { of, field }
|
||||||
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
};
|
};
|
||||||
res = Self {
|
res = Self {
|
||||||
@@ -69,6 +122,21 @@ impl ExprTy {
|
|||||||
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,
|
||||||
|
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 } => {
|
Self::If { cond, body } => {
|
||||||
write!(f, "if {} {}", cond.dsp(ctx), body.dsp(ctx))
|
write!(f, "if {} {}", cond.dsp(ctx), body.dsp(ctx))
|
||||||
}
|
}
|
||||||
@@ -88,6 +156,12 @@ impl ExprTy {
|
|||||||
write!(f, "}}")?;
|
write!(f, "}}")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Self::Import(ident) => {
|
||||||
|
write!(f, "import {ident}")
|
||||||
|
}
|
||||||
|
Self::Break => {
|
||||||
|
write!(f, "break")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,7 +211,12 @@ impl Expr {
|
|||||||
ctx.expect(Token::CloseCurly)?;
|
ctx.expect(Token::CloseCurly)?;
|
||||||
ExprTy::Block(body)
|
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 {
|
Ok(Self {
|
||||||
ty,
|
ty,
|
||||||
@@ -179,8 +258,13 @@ impl Expr {
|
|||||||
| ExprTy::If { body, .. }
|
| ExprTy::If { body, .. }
|
||||||
| ExprTy::Negate(body)
|
| ExprTy::Negate(body)
|
||||||
| ExprTy::Assign { val: body, .. } => body.ends_with_block(),
|
| ExprTy::Assign { val: body, .. } => body.ends_with_block(),
|
||||||
|
| ExprTy::Define { val: body, .. } => body.ends_with_block(),
|
||||||
ExprTy::Fn(f) => f.ends_with_block(),
|
ExprTy::Fn(f) => f.ends_with_block(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn needs_semicolon(&self) -> bool {
|
||||||
|
!self.ends_with_block()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use super::*;
|
|||||||
|
|
||||||
pub struct Func {
|
pub struct Func {
|
||||||
args: Vec<Param>,
|
args: Vec<Param>,
|
||||||
name: Option<Ident>,
|
|
||||||
ret: Option<Type>,
|
ret: Option<Type>,
|
||||||
body: Expr,
|
body: Expr,
|
||||||
span: Span,
|
span: Span,
|
||||||
@@ -10,14 +9,6 @@ pub struct Func {
|
|||||||
|
|
||||||
impl Node for Func {
|
impl Node for Func {
|
||||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
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)?;
|
ctx.expect(Token::OpenParen)?;
|
||||||
let args = ctx.list(Token::Comma, Token::CloseParen)?;
|
let args = ctx.list(Token::Comma, Token::CloseParen)?;
|
||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
@@ -29,16 +20,12 @@ impl Node for Func {
|
|||||||
args,
|
args,
|
||||||
ret,
|
ret,
|
||||||
body,
|
body,
|
||||||
name,
|
|
||||||
span: ctx.span(),
|
span: ctx.span(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
write!(f, "fn")?;
|
write!(f, "fn")?;
|
||||||
if let Some(name) = &self.name {
|
|
||||||
write!(f, " {name}")?;
|
|
||||||
}
|
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
if let Some((last, rest)) = self.args.split_last() {
|
if let Some((last, rest)) = self.args.split_last() {
|
||||||
for arg in rest {
|
for arg in rest {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ impl Node for Ident {
|
|||||||
fn parse(ctx: &mut super::ParseCtx) -> Result<Self, crate::io::CompilerMsg> {
|
fn parse(ctx: &mut super::ParseCtx) -> Result<Self, crate::io::CompilerMsg> {
|
||||||
match ctx.expect_next()? {
|
match ctx.expect_next()? {
|
||||||
Token::Ident(ident) => Ok(ctx.ident(ident)),
|
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 expr;
|
||||||
mod func;
|
mod func;
|
||||||
mod ident;
|
mod ident;
|
||||||
mod item;
|
|
||||||
mod param;
|
mod param;
|
||||||
mod struct_;
|
mod struct_;
|
||||||
mod ty;
|
mod ty;
|
||||||
@@ -10,7 +9,6 @@ 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 ty::*;
|
pub use ty::*;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ impl Node for Type {
|
|||||||
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
fn parse(ctx: &mut ParseCtx) -> Result<Self, CompilerMsg> {
|
||||||
Ok(match ctx.expect_next()? {
|
Ok(match ctx.expect_next()? {
|
||||||
Token::Ident(s) => Self::Ident(ctx.ident(s)),
|
Token::Ident(s) => Self::Ident(ctx.ident(s)),
|
||||||
t => ctx.unexpected(&t, "a type")?,
|
t => ctx.unexpected(t, "a type")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+84
-12
@@ -1,23 +1,95 @@
|
|||||||
use crate::{
|
use std::{
|
||||||
io::CompilerOutput,
|
collections::{HashMap, HashSet},
|
||||||
ir::{Ir, Namespace},
|
path::Path,
|
||||||
parser::{self, parse_file},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse_program(path: &str, output: &mut CompilerOutput) -> Option<Ir> {
|
use crate::{
|
||||||
|
io::{CompilerMsg, CompilerOutput, Span},
|
||||||
|
ir::Ir,
|
||||||
|
parser::{self, ExprTy, Ident, Node, parse_file},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parse_program(path: impl AsRef<Path>, output: &mut CompilerOutput) -> Option<Ir> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
let mut imports = Imports::default();
|
||||||
|
let dir = path.parent().unwrap();
|
||||||
|
imports.add(path.file_stem().unwrap().to_str().unwrap());
|
||||||
|
while let Some(next) = imports.new.pop() {
|
||||||
|
imports.done.insert(next.clone());
|
||||||
|
let path = dir.join(next + ".lang");
|
||||||
|
println!("=== {path:?}");
|
||||||
let root = parse_file(path, output)?;
|
let root = parse_file(path, output)?;
|
||||||
let mut ir = Ir::default();
|
print!("{}", root.new_dsp());
|
||||||
add_defs(ir.root(), &root);
|
let defs = scan(&mut imports, &root, output);
|
||||||
|
for (name, spans) in &defs.duplicates {
|
||||||
|
output.error(CompilerMsg {
|
||||||
|
msg: format!("Multiple definitions found for {name}"),
|
||||||
|
spans: spans.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !output.errors.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ir = Ir::default();
|
||||||
Some(ir)
|
Some(ir)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_defs(namespace: &mut Namespace, body: &parser::Body) {
|
pub fn scan(imports: &mut Imports, body: &parser::Body, output: &mut CompilerOutput) -> Defs {
|
||||||
|
let mut defs = Defs::default();
|
||||||
for item in &body.items {
|
for item in &body.items {
|
||||||
match &item.ty {
|
match &item.ty {
|
||||||
parser::ItemTy::Let { name, ty, val } => todo!(),
|
ExprTy::Define { target, const_, .. } if *const_ => match &target.ty {
|
||||||
parser::ItemTy::Fn(func) => todo!(),
|
ExprTy::Ident(name) => defs.add(name),
|
||||||
parser::ItemTy::Expr(expr) => todo!(),
|
_ => output.error(("Invalid left hand side of definition", target.span)),
|
||||||
parser::ItemTy::Import(ident) => todo!(),
|
},
|
||||||
|
ExprTy::Import(import) => {
|
||||||
|
defs.add(import);
|
||||||
|
imports.add(&import.name);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
defs
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Defs {
|
||||||
|
map: HashMap<String, (usize, Span)>,
|
||||||
|
duplicates: HashMap<String, Vec<Span>>,
|
||||||
|
next_id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Defs {
|
||||||
|
pub fn add(&mut self, ident: &Ident) {
|
||||||
|
if let Some(def) = self.map.get(&ident.name) {
|
||||||
|
if let Some(spans) = self.duplicates.get_mut(&ident.name) {
|
||||||
|
spans.push(ident.span);
|
||||||
|
} else {
|
||||||
|
self.duplicates
|
||||||
|
.insert(ident.name.clone(), vec![def.1, ident.span]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.map
|
||||||
|
.insert(ident.name.clone(), (self.next_id, ident.span));
|
||||||
|
self.next_id += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Imports {
|
||||||
|
done: HashSet<String>,
|
||||||
|
new: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Imports {
|
||||||
|
pub fn add(&mut self, name: &str) {
|
||||||
|
if self.done.contains(name) || self.new.iter().any(|v| v == name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.new.push(name.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-6
@@ -1,14 +1,17 @@
|
|||||||
modl other;
|
x : i32 = 3;
|
||||||
|
|
||||||
let x: i32 = 3;
|
|
||||||
while true {
|
while true {
|
||||||
print("hello");
|
print("hello");
|
||||||
print(x);
|
print(x);
|
||||||
};
|
other.thing();
|
||||||
|
thing();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
let y = true;
|
y :: true;
|
||||||
|
|
||||||
if y => print("hello");
|
if y => print("hello");
|
||||||
|
|
||||||
fn thing() {
|
thing :: fn() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import other;
|
||||||
|
|||||||
+3
-1
@@ -1,3 +1,5 @@
|
|||||||
fn thing() {
|
thing :: fn() {
|
||||||
print("hello from other");
|
print("hello from other");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import main;
|
||||||
|
|||||||
Reference in New Issue
Block a user