start of ir

This commit is contained in:
2024-10-17 23:40:09 -04:00
parent e33420e91f
commit b15a40c4d9
19 changed files with 268 additions and 81 deletions

View File

@@ -19,6 +19,7 @@ fn main() {
let a = 3;
b
};
exit(3, let, "hello");
}
fn test() {

View File

@@ -1,4 +1,4 @@
fn main() {
let x = &"Hello World!";
print(x);
let x = 3;
exit(x);
}

View File

@@ -10,7 +10,7 @@ mod program;
mod riscv64;
mod target;
use program::*;
pub use program::*;
pub fn main() {
use std::io::prelude::*;

View File

@@ -59,13 +59,13 @@ impl Deref for WritableSymbol {
}
}
pub struct SymMap<I: Instr> {
pub struct SymMap<I> {
i: usize,
ro_data: Vec<(Vec<u8>, Symbol)>,
functions: Vec<(Vec<I>, Symbol)>,
}
impl<I: Instr> SymMap<I> {
impl<I> SymMap<I> {
pub fn new() -> Self {
Self {
i: 0,

View File

@@ -3,7 +3,13 @@ use crate::compiler::program::{Addr, Instr, SymTable, Symbol};
use super::*;
pub enum AsmInstruction {
Add(Reg, Reg, Reg),
Addi(Reg, Reg, i32),
Andi(Reg, Reg, i32),
Slli(Reg, Reg, i32),
Srli(Reg, Reg, i32),
Sd(Reg, i32, Reg),
Mv(Reg, Reg),
La(Reg, Symbol),
Jal(Reg, i32),
Call(Symbol),
@@ -16,7 +22,13 @@ pub enum AsmInstruction {
impl Instr for AsmInstruction {
fn push(&self, data: &mut Vec<u8>, sym_map: &SymTable, pos: Addr, missing: bool) -> Option<Symbol> {
let last = match self {
Self::Add(dest, src1, src2) => add(*dest, *src1, *src2),
Self::Addi(dest, src, imm) => addi(*dest, *src, BitsI32::new(*imm)),
Self::Andi(dest, src, imm) => andi(*dest, *src, BitsI32::new(*imm)),
Self::Slli(dest, src, imm) => slli(*dest, *src, BitsI32::new(*imm)),
Self::Srli(dest, src, imm) => srli(*dest, *src, BitsI32::new(*imm)),
Self::Sd(src, offset, base) => sd(*src, BitsI32::new(*offset), *base),
Self::Mv(dest, src) => addi(*dest, *src, BitsI32::new(0)),
Self::La(dest, sym) => {
if let Some(addr) = sym_map.get(*sym) {
let offset = addr.val() as i32 - pos.val() as i32;

View File

@@ -18,14 +18,14 @@ impl Instruction {
pub type Funct3 = Bits32<2, 0>;
pub const fn r_type(
funct7: u32,
funct7: Bits32<6, 0>,
rs2: Reg,
rs1: Reg,
funct3: Bits32<2, 0>,
rd: Reg,
opcode: u32,
) -> I {
I((funct7 << 25)
I((funct7.val() << 25)
+ (rs2.val() << 20)
+ (rs1.val() << 15)
+ (funct3.val() << 12)

View File

@@ -31,9 +31,21 @@ pub const fn sw(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
pub const fn sd(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
s_type(src, base, width::D, offset.to_u(), STORE)
}
pub const fn add(dest: Reg, src1: Reg, src2: Reg) -> I {
r_type(Bits32::new(0), src2, src1, ADD, dest, OP)
}
pub const fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I {
i_type(imm.to_u(), src, ADD, dest, IMM_OP)
}
pub const fn andi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I {
i_type(imm.to_u(), src, AND, dest, IMM_OP)
}
pub const fn slli(dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I {
i_type(Bits32::new(imm.to_u().val()), src, SLL, dest, IMM_OP)
}
pub const fn srli(dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I {
i_type(Bits32::new(imm.to_u().val()), src, SR, dest, IMM_OP)
}
pub const fn jal(dest: Reg, offset: BitsI32<20, 1>) -> I {
j_type(offset.to_u(), dest, JAL)
}

View File

@@ -1,2 +1,128 @@
use std::collections::HashMap;
use crate::parser::{Body, Expr, Function, Ident, Literal, ParserError, Statement, Unresolved};
#[derive(Debug)]
pub enum IRInstruction {
Li(IRIdent, Literal),
Mv(IRIdent, IRIdent),
}
#[derive(Debug)]
pub struct IRFunction {
instructions: Vec<IRInstruction>,
}
impl Function<Unresolved> {
pub fn lower(&self, functions: &mut Vec<IRFunction>, map: &mut Namespace) -> Result<(), ParserError> {
let Ok(name) = &self.name.inner else {
return Ok(());
};
if map.get(name).is_some() {
Err(ParserError {
msg: format!("Already something named '{:?}'", self.name),
spans: vec![self.name.span],
})
} else {
map.add(name);
let mut instructions = Vec::new();
self.body.as_ref().map(|b| b.lower(map, &mut instructions));
functions.push(IRFunction { instructions });
Ok(())
}
}
}
impl Body<Unresolved> {
pub fn lower(&self, map: &Namespace, instructions: &mut Vec<IRInstruction>) {
let mut map = map.clone();
for statement in &self.statements {
let Ok(statement) = &statement.inner else {
continue;
};
match statement {
Statement::Let(name, expr) => {
let Ok(name) = &name.inner else {
continue;
};
let name = map.add(name);
let Ok(expr) = &expr.inner else {
continue;
};
if let Ok(Some(res)) = expr.lower(&map, instructions) {
instructions.push(match res {
ExprResult::Lit(l) => IRInstruction::Li(name, l),
ExprResult::Ident(i) => IRInstruction::Mv(name, i),
});
}
}
Statement::Return(e) => todo!(),
Statement::Expr(expr) => todo!(),
}
}
}
}
impl Expr<Unresolved> {
pub fn lower(
&self,
map: &Namespace,
instructions: &mut Vec<IRInstruction>,
) -> Result<Option<ExprResult>, String> {
Ok(match self {
Expr::Lit(l) => {
let Ok(l) = &l.inner else {return Ok(None)};
Some(ExprResult::Lit(l.clone()))
},
Expr::Ident(i) => {
let Ok(i) = &i.inner else {return Ok(None)};
let Some(id) = map.get(i) else {
return Err(format!("Identifier '{:?}' not found", i));
};
Some(ExprResult::Ident(id))
}
Expr::BinaryOp(_, _, _) => todo!(),
Expr::UnaryOp(_, _) => todo!(),
Expr::Block(_) => todo!(),
Expr::Call(_, _) => todo!(),
Expr::Group(_) => todo!(),
})
}
}
enum ExprResult {
Lit(Literal),
Ident(IRIdent),
}
#[derive(Debug, Clone)]
pub struct Namespace {
pub cur: usize,
pub map: HashMap<String, IRIdent>,
}
impl Namespace {
pub fn new() -> Self {
Self {
cur: 0,
map: HashMap::new(),
}
}
pub fn get(&self, name: &Ident) -> Option<IRIdent> {
self.map.get(name.val()).copied()
}
pub fn reserve(&mut self) -> IRIdent {
let id = IRIdent ( self.cur );
self.cur += 1;
id
}
pub fn add(&mut self, name: &Ident) -> IRIdent {
let id = self.reserve();
self.map.insert(name.val().to_string(), id);
id
}
}
#[derive(Debug, Clone, Copy)]
pub struct IRIdent (usize);

View File

@@ -1,6 +1,8 @@
mod v1;
mod v2;
pub use v1::*;
pub fn main() {
let arg = std::env::args_os().nth(1);
if let Some(path) = arg {

View File

@@ -36,6 +36,14 @@ impl<'a> TokenCursor<'a> {
.is_some_and(|n| n.token != Token::Symbol(symbol))
{}
}
pub fn seek_syms(&mut self, syms: &[Symbol]) {
while self
.peek()
.is_some_and(|n| !syms.iter().any(|s| n.is_symbol(*s)))
{
self.next();
}
}
pub fn seek(&mut self, f: impl Fn(&TokenInstance) -> bool) -> Option<&TokenInstance> {
loop {
if f(self.peek()?) {
@@ -53,13 +61,6 @@ impl<'a> TokenCursor<'a> {
pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserError> {
self.peek().ok_or(ParserError::unexpected_end())
}
pub fn expect_ident(&mut self) -> Result<String, ParserError> {
let i = self.expect_next()?;
let Token::Ident(n) = &i.token else {
return Err(ParserError::unexpected_token(&i, "an identifier"));
};
Ok(n.to_string())
}
pub fn chars(&mut self) -> &mut CharCursor<'a> {
&mut self.cursor
}

View File

@@ -7,13 +7,12 @@ use super::{
use crate::util::Padder;
pub struct Body<R: MaybeResolved> {
statements: Vec<Node<Statement<R>, R>>,
pub statements: Vec<Node<Statement<R>, R>>,
}
impl Parsable for Body<Unresolved> {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
let mut statements = Vec::new();
let statement_end = &[Symbol::Semicolon, Symbol::CloseCurly];
cursor.expect_sym(Symbol::OpenCurly)?;
if cursor.expect_peek()?.is_symbol(Symbol::CloseCurly) {
cursor.next();
@@ -44,13 +43,12 @@ impl Parsable for Body<Unresolved> {
let res = Statement::parse_node(cursor, errors);
statements.push(res.node);
expect_semi = true;
if res.recover
&& cursor
.seek(|t| t.is_symbol_and(|s| statement_end.contains(&s)))
.is_none()
{
recover = true;
break;
if res.recover {
cursor.seek_syms(&[Symbol::Semicolon, Symbol::CloseCurly]);
if cursor.peek().is_none() {
recover = true;
break;
}
}
}
ParseResult::from_recover(Self { statements }, recover)

View File

@@ -1,16 +1,16 @@
use std::fmt::{Debug, Write};
use super::token::{Symbol, Token};
use super::{
BinaryOperator, Body, Literal, MaybeResolved, Node, NodeParsable, Parsable, ParseResult,
ParserError, ParserErrors, Resolvable, Resolved, TokenCursor, UnaryOperator, Unresolved,
BinaryOperator, Body, Ident, Literal, MaybeResolved, Node, NodeParsable, Parsable, ParseResult,
ParserError, ParserErrors, Resolvable, Resolved, Symbol, TokenCursor, UnaryOperator,
Unresolved,
};
type BoxNode<R> = Node<Box<Expr<R>>, R>;
pub enum Expr<R: MaybeResolved> {
Lit(Node<Literal, R>),
Ident(String),
Ident(Node<Ident, R>),
BinaryOp(BinaryOperator, BoxNode<R>, BoxNode<R>),
UnaryOp(UnaryOperator, BoxNode<R>),
Block(Node<Body<R>, R>),
@@ -53,16 +53,12 @@ impl Parsable for Expr<Unresolved> {
} else if let Some(val) = Node::maybe_parse(cursor, errors) {
Self::Lit(val)
} else {
let next = cursor.peek().unwrap();
match &next.token {
Token::Ident(name) => {
let name = name.to_string();
cursor.next();
Self::Ident(name)
}
_ => {
return ParseResult::Err(ParserError::unexpected_token(next, "an expression"));
}
let res = Node::parse(cursor, &mut ParserErrors::new());
if res.node.is_ok() {
Self::Ident(res.node)
} else {
let next = cursor.expect_peek()?;
return ParseResult::Err(ParserError::unexpected_token(next, "an expression"));
}
};
let Some(mut next) = cursor.peek() else {
@@ -71,13 +67,21 @@ impl Parsable for Expr<Unresolved> {
while next.is_symbol(Symbol::OpenParen) {
cursor.next();
let mut args = Vec::new();
while !cursor.expect_peek()?.is_symbol(Symbol::CloseParen) {
loop {
let next = cursor.expect_peek()?;
if next.is_symbol(Symbol::CloseParen) {
break;
}
let res = Node::<Expr<Unresolved>, Unresolved>::parse(cursor, errors);
args.push(res.node);
if res.recover {
cursor.seek_sym(Symbol::CloseParen);
cursor.seek_syms(&[Symbol::CloseParen, Symbol::Comma]);
}
let next = cursor.expect_peek()?;
if !next.is_symbol(Symbol::Comma) {
break;
}
cursor.next();
}
cursor.expect_sym(Symbol::CloseParen)?;
let end = cursor.prev_end();
@@ -118,7 +122,7 @@ impl Resolvable<Expr<Resolved>> for Expr<Unresolved> {
fn resolve(self) -> Result<Expr<Resolved>, ()> {
Ok(match self {
Expr::Lit(l) => Expr::Lit(l.resolve()?),
Expr::Ident(n) => Expr::Ident(n),
Expr::Ident(n) => Expr::Ident(n.resolve()?),
Expr::BinaryOp(o, e1, e2) => Expr::BinaryOp(o, e1.resolve()?, e2.resolve()?),
Expr::UnaryOp(o, e) => Expr::UnaryOp(o, e.resolve()?),
Expr::Block(b) => Expr::Block(b.resolve()?),
@@ -137,7 +141,7 @@ impl Debug for Expr<Unresolved> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expr::Lit(c) => c.fmt(f)?,
Expr::Ident(n) => f.write_str(n)?,
Expr::Ident(n) => n.fmt(f)?,
Expr::Block(b) => b.fmt(f)?,
Expr::BinaryOp(op, e1, e2) => {
write!(f, "({:?}", *e1)?;

View File

@@ -1,28 +1,28 @@
use super::{
Body, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved,
Symbol, TokenCursor, Unresolved,
Body, Ident, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable,
Resolved, Symbol, TokenCursor, Unresolved,
};
use std::fmt::Debug;
pub struct Function<R: MaybeResolved> {
pub name: String,
pub name: Node<Ident, R>,
pub body: Node<Body<R>, R>,
}
impl Parsable for Function<Unresolved> {
fn parse(cursor: &mut TokenCursor, errors: &mut ParserErrors) -> ParseResult<Self> {
cursor.expect_kw(Keyword::Fn)?;
let name = cursor.expect_ident()?;
let name = Node::parse(cursor, errors)?;
cursor.expect_sym(Symbol::OpenParen)?;
cursor.expect_sym(Symbol::CloseParen)?;
Node::parse(cursor, errors).map(|body| Self {name, body})
Node::parse(cursor, errors).map(|body| Self { name, body })
}
}
impl Debug for Function<Unresolved> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("fn ")?;
f.write_str(&self.name)?;
self.name.fmt(f)?;
f.write_str("() ")?;
self.body.fmt(f)?;
Ok(())
@@ -32,7 +32,7 @@ impl Debug for Function<Unresolved> {
impl Resolvable<Function<Resolved>> for Function<Unresolved> {
fn resolve(self) -> Result<Function<Resolved>, ()> {
Ok(Function {
name: self.name,
name: self.name.resolve()?,
body: self.body.resolve()?,
})
}

View File

@@ -0,0 +1,34 @@
use std::fmt::Debug;
use super::{Parsable, ParseResult, ParserError, Resolvable, Token};
pub struct Ident(String);
impl Ident {
pub fn val(&self) -> &String {
&self.0
}
}
impl Parsable for Ident {
fn parse(cursor: &mut super::TokenCursor, errors: &mut super::ParserErrors) -> ParseResult<Self> {
let next = cursor.expect_peek()?;
let Token::Ident(name) = &next.token else {
return ParseResult::Err(ParserError::unexpected_token(next, "an identifier"));
};
let name = name.to_string();
cursor.next();
ParseResult::Ok(Self(name))
}
}
impl Debug for Ident {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Resolvable<Ident> for Ident {
fn resolve(self) -> Result<Ident, ()> {
Ok(self)
}
}

View File

@@ -1,4 +1,6 @@
use super::{CharCursor, MaybeParsable, ParserError, ParserErrors, Resolvable, Symbol, Token, TokenCursor};
use super::{
CharCursor, MaybeParsable, ParserError, ParserErrors, Resolvable, Symbol, Token, TokenCursor,
};
use std::fmt::Debug;
#[derive(Clone, PartialEq, Eq)]
@@ -17,7 +19,10 @@ pub struct Number {
}
impl MaybeParsable for Literal {
fn maybe_parse(cursor: &mut TokenCursor, _: &mut ParserErrors) -> Result<Option<Self>, ParserError> {
fn maybe_parse(
cursor: &mut TokenCursor,
_: &mut ParserErrors,
) -> Result<Option<Self>, ParserError> {
let inst = cursor.expect_peek()?;
let mut res = match &inst.token {
Token::Symbol(Symbol::SingleQuote) => {
@@ -42,15 +47,14 @@ impl MaybeParsable for Literal {
_ => return Ok(None),
};
cursor.next();
if let Some(next) = cursor.peek() {
if let Self::Number(num) = &mut res {
if let Token::Symbol(Symbol::Dot) = next.token {
let chars = cursor.chars();
if let Some(c) = chars.peek() {
if c.is_ascii_digit() {
if let (Some(next), Self::Number(num)) = (cursor.peek(), &mut res) {
if next.token.is_symbol(Symbol::Dot) {
cursor.next();
if let Some(next) = cursor.peek() {
if let Token::Ident(i) = &next.token {
if i.chars().next().unwrap().is_ascii_digit() {
num.decimal = Some(i.to_string());
cursor.next();
let decimal = cursor.expect_ident()?;
num.decimal = Some(decimal);
}
}
}
@@ -114,4 +118,3 @@ impl Debug for Number {
Ok(())
}
}

View File

@@ -4,7 +4,8 @@ mod func;
mod module;
mod op;
mod statement;
mod val;
mod lit;
mod ident;
pub use body::*;
pub use expr::*;
@@ -12,6 +13,7 @@ pub use func::*;
pub use module::*;
pub use op::*;
pub use statement::*;
pub use val::*;
pub use lit::*;
pub use ident::*;
use super::*;

View File

@@ -1,10 +1,10 @@
use std::fmt::{Debug, Write};
use super::{
Expr, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved, Symbol, Token, TokenCursor, Unresolved
Expr, Ident, Keyword, MaybeResolved, Node, Parsable, ParseResult, ParserErrors, Resolvable, Resolved, Symbol, Token, TokenCursor, Unresolved
};
pub enum Statement<R: MaybeResolved> {
Let(String, Node<Expr<R>, R>),
Let(Node<Ident, R>, Node<Expr<R>, R>),
Return(Node<Expr<R>, R>),
Expr(Node<Expr<R>, R>),
}
@@ -15,7 +15,7 @@ impl Parsable for Statement<Unresolved> {
match next.token {
Token::Keyword(Keyword::Let) => {
cursor.next();
let name = cursor.expect_ident()?;
let name = Node::parse(cursor, errors)?;
cursor.expect_sym(Symbol::Equals)?;
Node::parse(cursor, errors).map(|expr| Self::Let(name, expr))
}
@@ -31,7 +31,7 @@ impl Parsable for Statement<Unresolved> {
impl Resolvable<Statement<Resolved>> for Statement<Unresolved> {
fn resolve(self) -> Result<Statement<Resolved>, ()> {
Ok(match self {
Self::Let(i, e) => Statement::Let(i, e.resolve()?),
Self::Let(i, e) => Statement::Let(i.resolve()?, e.resolve()?),
Self::Return(e) => Statement::Return(e.resolve()?),
Self::Expr(e) => Statement::Expr(e.resolve()?),
})
@@ -43,7 +43,7 @@ impl Debug for Statement<Unresolved> {
match self {
Statement::Let(n, e) => {
f.write_str("let ")?;
f.write_str(n)?;
n.fmt(f);
f.write_str(" = ")?;
e.fmt(f)?;
f.write_char(';')?;

View File

@@ -68,17 +68,6 @@ impl<T, U> FromResidual<ParseResult<T>> for ParseResult<U> {
}
}
impl<T> ParseResult<T> {
pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> ParseResult<U> {
match self {
Self::Ok(v) => ParseResult::Ok(op(v)),
Self::Recover(v) => ParseResult::Recover(op(v)),
Self::Err(e) => ParseResult::Err(e),
Self::SubErr => ParseResult::SubErr,
}
}
}
pub struct NodeParseResult<T> {
pub node: Node<T, Unresolved>,
pub recover: bool,
@@ -116,8 +105,8 @@ impl<T> Try for NodeParseResult<T> {
}
impl<T> FromResidual for NodeParseResult<T> {
fn from_residual(residual: <Self as Try>::Residual) -> Self {
// ???
fn from_residual(_: <Self as Try>::Residual) -> Self {
// I hope this is unreachable ???
unreachable!()
}
}

View File

@@ -32,6 +32,7 @@ pub enum Symbol {
DoubleAmpersand,
Pipe,
DoublePipe,
Comma,
}
impl Symbol {
@@ -65,6 +66,7 @@ impl Symbol {
'!' => Self::Bang,
'&' => Self::Ampersand,
'|' => Self::Pipe,
',' => Self::Comma,
_ => return None,
})
}
@@ -93,11 +95,11 @@ impl Symbol {
Self::Ampersand => match next {
'&' => Self::DoubleAmpersand,
_ => return,
}
},
Self::Pipe => match next {
'&' => Self::DoublePipe,
_ => return,
}
},
_ => return,
};
cursor.advance();
@@ -128,6 +130,7 @@ impl Symbol {
Self::SingleQuote => "'",
Self::DoubleQuote => "\"",
Self::Bang => "!",
Self::Comma => ",",
Self::Ampersand => "&",
Self::DoubleAmpersand => "&&",
Self::Pipe => "|",