type checking !?!?
This commit is contained in:
@@ -1,33 +1,33 @@
|
|||||||
fn start() {
|
fn start() {
|
||||||
print("Helld!\n");
|
print("Helld!\n");
|
||||||
print("Hello World!!!!!\n");
|
print("Hello World!!!!!\n");
|
||||||
thinger();
|
thinger();
|
||||||
print("what\n");
|
print("what\n");
|
||||||
exit(39);
|
exit(39);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn thinger() {
|
fn thinger() {
|
||||||
print("estamos jugando\n");
|
print("estamos jugando\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unused() {
|
fn unused() {
|
||||||
print("el unused\n");
|
print("el unused\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print(msg: slice<8>) {
|
fn print(msg: slice<8>) {
|
||||||
asm (a1 = msg) {
|
asm (a1 = msg) {
|
||||||
ld a2, 8, a1
|
ld a2, 8, a1
|
||||||
ld a1, 0, a1
|
ld a1, 0, a1
|
||||||
li a0, 1
|
li a0, 1
|
||||||
li a7, 64
|
li a7, 64
|
||||||
ecall
|
ecall
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exit(status: 64) {
|
fn exit(status: 64) {
|
||||||
asm (a0 = status) {
|
asm (a0 = status) {
|
||||||
ld a0, 0, a0
|
ld a0, 0, a0
|
||||||
li a7, 93
|
li a7, 93
|
||||||
ecall
|
ecall
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
5
src/common/mod.rs
Normal file
5
src/common/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
mod output;
|
||||||
|
mod file;
|
||||||
|
|
||||||
|
pub use output::*;
|
||||||
|
pub use file::*;
|
||||||
64
src/common/output.rs
Normal file
64
src/common/output.rs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
use super::{FilePos, FileSpan};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CompilerMsg {
|
||||||
|
pub msg: String,
|
||||||
|
pub spans: Vec<FileSpan>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CompilerOutput {
|
||||||
|
pub errs: Vec<CompilerMsg>,
|
||||||
|
pub hints: Vec<CompilerMsg>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompilerMsg {
|
||||||
|
pub fn from_msg(msg: String) -> Self {
|
||||||
|
Self {
|
||||||
|
msg,
|
||||||
|
spans: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_span(span: FileSpan, msg: String) -> Self {
|
||||||
|
Self {
|
||||||
|
msg,
|
||||||
|
spans: vec![span],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn at(pos: FilePos, msg: String) -> Self {
|
||||||
|
Self {
|
||||||
|
msg,
|
||||||
|
spans: vec![FileSpan::at(pos)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn write_for(&self, ty: &str, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
|
||||||
|
let after = if self.spans.is_empty() { "" } else { ":" };
|
||||||
|
writeln!(writer, "{}: {}{}", ty, self.msg, after)?;
|
||||||
|
for span in &self.spans {
|
||||||
|
span.write_for(writer, file)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompilerOutput {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
errs: Vec::new(),
|
||||||
|
hints: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn err(&mut self, msg: CompilerMsg) {
|
||||||
|
self.errs.push(msg);
|
||||||
|
}
|
||||||
|
pub fn hint(&mut self, msg: CompilerMsg) {
|
||||||
|
self.hints.push(msg);
|
||||||
|
}
|
||||||
|
pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) {
|
||||||
|
for err in &self.errs {
|
||||||
|
err.write_for("error", out, file).unwrap();
|
||||||
|
}
|
||||||
|
for hint in &self.hints {
|
||||||
|
hint.write_for("hint", out, file).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,13 @@ pub enum LinkerInstruction {
|
|||||||
Slli { dest: Reg, src: Reg, imm: i32 },
|
Slli { dest: Reg, src: Reg, imm: i32 },
|
||||||
Srli { dest: Reg, src: Reg, imm: i32 },
|
Srli { dest: Reg, src: Reg, imm: i32 },
|
||||||
Sd { src: Reg, offset: i32, base: Reg },
|
Sd { src: Reg, offset: i32, base: Reg },
|
||||||
|
Sw { src: Reg, offset: i32, base: Reg },
|
||||||
|
Sh { src: Reg, offset: i32, base: Reg },
|
||||||
|
Sb { src: Reg, offset: i32, base: Reg },
|
||||||
Ld { dest: Reg, offset: i32, base: Reg },
|
Ld { dest: Reg, offset: i32, base: Reg },
|
||||||
|
Lw { dest: Reg, offset: i32, base: Reg },
|
||||||
|
Lh { dest: Reg, offset: i32, base: Reg },
|
||||||
|
Lb { dest: Reg, offset: i32, base: Reg },
|
||||||
Mv { dest: Reg, src: Reg },
|
Mv { dest: Reg, src: Reg },
|
||||||
La { dest: Reg, src: Symbol },
|
La { dest: Reg, src: Symbol },
|
||||||
Jal { dest: Reg, offset: i32 },
|
Jal { dest: Reg, offset: i32 },
|
||||||
@@ -36,7 +42,13 @@ impl Instr for LinkerInstruction {
|
|||||||
Self::Slli { dest, src, imm } => slli(*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::Srli { dest, src, imm } => srli(*dest, *src, BitsI32::new(*imm)),
|
||||||
Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base),
|
Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base),
|
||||||
|
Self::Sw { src, offset, base } => sw(*src, BitsI32::new(*offset), *base),
|
||||||
|
Self::Sh { src, offset, base } => sh(*src, BitsI32::new(*offset), *base),
|
||||||
|
Self::Sb { src, offset, base } => sb(*src, BitsI32::new(*offset), *base),
|
||||||
Self::Ld { dest, offset, base } => ld(*dest, BitsI32::new(*offset), *base),
|
Self::Ld { dest, offset, base } => ld(*dest, BitsI32::new(*offset), *base),
|
||||||
|
Self::Lw { dest, offset, base } => lw(*dest, BitsI32::new(*offset), *base),
|
||||||
|
Self::Lh { dest, offset, base } => lh(*dest, BitsI32::new(*offset), *base),
|
||||||
|
Self::Lb { dest, offset, base } => lb(*dest, BitsI32::new(*offset), *base),
|
||||||
Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)),
|
Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)),
|
||||||
Self::La { dest, src } => {
|
Self::La { dest, src } => {
|
||||||
if let Some(addr) = sym_map.get(*src) {
|
if let Some(addr) = sym_map.get(*src) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
compiler::{arch::riscv64::Reg, create_program, Addr},
|
compiler::{arch::riscv64::Reg, create_program, Addr},
|
||||||
ir::{
|
ir::{
|
||||||
arch::riscv64::{RV64Instruction as AI, RegRef},
|
arch::riscv64::{RV64Instruction as AI, RegRef},
|
||||||
IRLInstruction as IRI, IRLProgram, Len, Size, Symbol, VarID,
|
IRLInstruction as IRI, IRLProgram, Len, Size,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,6 +40,54 @@ fn mov_mem(
|
|||||||
len -= 8;
|
len -= 8;
|
||||||
off += 8;
|
off += 8;
|
||||||
}
|
}
|
||||||
|
while len >= 4 {
|
||||||
|
v.extend([
|
||||||
|
LI::Lw {
|
||||||
|
dest: temp,
|
||||||
|
offset: src_offset + off,
|
||||||
|
base: src,
|
||||||
|
},
|
||||||
|
LI::Sw {
|
||||||
|
src: temp,
|
||||||
|
offset: dest_offset + off,
|
||||||
|
base: dest,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
len -= 4;
|
||||||
|
off += 4;
|
||||||
|
}
|
||||||
|
while len >= 2 {
|
||||||
|
v.extend([
|
||||||
|
LI::Lh {
|
||||||
|
dest: temp,
|
||||||
|
offset: src_offset + off,
|
||||||
|
base: src,
|
||||||
|
},
|
||||||
|
LI::Sh {
|
||||||
|
src: temp,
|
||||||
|
offset: dest_offset + off,
|
||||||
|
base: dest,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
len -= 2;
|
||||||
|
off += 2;
|
||||||
|
}
|
||||||
|
while len >= 1 {
|
||||||
|
v.extend([
|
||||||
|
LI::Lb {
|
||||||
|
dest: temp,
|
||||||
|
offset: src_offset + off,
|
||||||
|
base: src,
|
||||||
|
},
|
||||||
|
LI::Sb {
|
||||||
|
src: temp,
|
||||||
|
offset: dest_offset + off,
|
||||||
|
base: dest,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
len -= 1;
|
||||||
|
off += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(program: IRLProgram) -> (Vec<u8>, Option<Addr>) {
|
pub fn compile(program: IRLProgram) -> (Vec<u8>, Option<Addr>) {
|
||||||
|
|||||||
@@ -13,24 +13,33 @@ pub const fn ebreak() -> I {
|
|||||||
pub const fn auipc(dest: Reg, imm: BitsI32<31, 12>) -> I {
|
pub const fn auipc(dest: Reg, imm: BitsI32<31, 12>) -> I {
|
||||||
u_type(imm.to_u(), dest, AUIPC)
|
u_type(imm.to_u(), dest, AUIPC)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn ld(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
pub const fn ld(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||||
i_type(offset.to_u(), base, width::D, dest, LOAD)
|
i_type(offset.to_u(), base, width::D, dest, LOAD)
|
||||||
}
|
}
|
||||||
pub const fn lw(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
pub const fn lw(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||||
i_type(offset.to_u(), base, width::W, dest, LOAD)
|
i_type(offset.to_u(), base, width::W, dest, LOAD)
|
||||||
}
|
}
|
||||||
|
pub const fn lh(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||||
|
i_type(offset.to_u(), base, width::H, dest, LOAD)
|
||||||
|
}
|
||||||
pub const fn lb(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
pub const fn lb(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||||
i_type(offset.to_u(), base, width::B, dest, LOAD)
|
i_type(offset.to_u(), base, width::B, dest, LOAD)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 sb(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
pub const fn sb(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||||
s_type(src, base, width::B, offset.to_u(), STORE)
|
s_type(src, base, width::B, offset.to_u(), STORE)
|
||||||
}
|
}
|
||||||
|
pub const fn sh(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||||
|
s_type(src, base, width::H, offset.to_u(), STORE)
|
||||||
|
}
|
||||||
pub const fn sw(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
pub const fn sw(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I {
|
||||||
s_type(src, base, width::W, offset.to_u(), STORE)
|
s_type(src, base, width::W, offset.to_u(), STORE)
|
||||||
}
|
}
|
||||||
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 {
|
pub const fn add(dest: Reg, src1: Reg, src2: Reg) -> I {
|
||||||
r_type(Bits32::new(0), src2, src1, ADD, dest, OP)
|
r_type(Bits32::new(0), src2, src1, ADD, dest, OP)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,33 @@
|
|||||||
use crate::{compiler::arch::riscv64::*, ir::VarID};
|
use crate::{
|
||||||
|
compiler::arch::riscv64::*,
|
||||||
|
ir::{VarID, VarInst},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum RV64Instruction {
|
pub enum RV64Instruction {
|
||||||
Ecall,
|
Ecall,
|
||||||
Li { dest: RegRef, imm: i64 },
|
Li {
|
||||||
Mv { dest: RegRef, src: RegRef },
|
dest: RegRef,
|
||||||
La { dest: RegRef, src: VarID },
|
imm: i64,
|
||||||
Ld { dest: RegRef, offset: i64, base: RegRef },
|
},
|
||||||
|
Mv {
|
||||||
|
dest: RegRef,
|
||||||
|
src: RegRef,
|
||||||
|
},
|
||||||
|
La {
|
||||||
|
dest: RegRef,
|
||||||
|
src: VarInst,
|
||||||
|
},
|
||||||
|
Ld {
|
||||||
|
dest: RegRef,
|
||||||
|
offset: i64,
|
||||||
|
base: RegRef,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum RegRef {
|
pub enum RegRef {
|
||||||
Var(VarID),
|
Var(VarInst),
|
||||||
Reg(Reg),
|
Reg(Reg),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::ir::{FnID, SymbolSpace};
|
use crate::ir::SymbolSpace;
|
||||||
|
|
||||||
use super::{IRLFunction, IRLInstruction, IRUInstruction, Len, Namespace, Symbol, VarID};
|
use super::{IRLFunction, IRLInstruction, IRUInstruction, IRUProgram, Len, Symbol, Type, VarID};
|
||||||
|
|
||||||
pub struct IRLProgram {
|
pub struct IRLProgram {
|
||||||
sym_space: SymbolSpace,
|
sym_space: SymbolSpace,
|
||||||
@@ -12,110 +12,116 @@ pub struct IRLProgram {
|
|||||||
// NOTE: there are THREE places here where I specify size (8)
|
// NOTE: there are THREE places here where I specify size (8)
|
||||||
|
|
||||||
impl IRLProgram {
|
impl IRLProgram {
|
||||||
pub fn create(ns: &Namespace) -> Option<Self> {
|
pub fn create(p: &IRUProgram) -> Result<Self, String> {
|
||||||
let mut start = None;
|
let mut start = None;
|
||||||
for (i, f) in ns.iter_fns() {
|
for (i, f) in p.iter_fns() {
|
||||||
if f?.name == "start" {
|
if f.name == "start" {
|
||||||
start = Some(i);
|
start = Some(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let start = start?;
|
let start = start.ok_or("no start method found")?;
|
||||||
let mut builder = SymbolSpace::with_entries(&[start]);
|
let mut builder = SymbolSpace::with_entries(&[start]);
|
||||||
let entry = builder.func(&start);
|
let entry = builder.func(&start);
|
||||||
while let Some((sym, i)) = builder.pop_fn() {
|
while let Some((sym, i)) = builder.pop_fn() {
|
||||||
let f = ns.fns[i.0].as_ref().unwrap();
|
let f = p.fns[i.0].as_ref().unwrap();
|
||||||
let mut instrs = Vec::new();
|
let mut instrs = Vec::new();
|
||||||
let mut stack = HashMap::new();
|
let mut stack = HashMap::new();
|
||||||
let mut makes_call = false;
|
let mut makes_call = false;
|
||||||
let mut alloc_stack = |i: &VarID| -> bool {
|
let mut alloc_stack = |i: VarID| -> bool {
|
||||||
let size = *stack
|
let size = *stack
|
||||||
.entry(*i)
|
.entry(i)
|
||||||
.or_insert(ns.size_of_var(i).expect("unsized type"));
|
.or_insert(p.size_of_var(i).expect("unsized type"));
|
||||||
size == 0
|
size == 0
|
||||||
};
|
};
|
||||||
for i in &f.instructions {
|
for i in &f.instructions {
|
||||||
match i {
|
match &i.i {
|
||||||
IRUInstruction::Mv { dest, src } => {
|
IRUInstruction::Mv { dest, src } => {
|
||||||
if alloc_stack(dest) {
|
if alloc_stack(dest.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
instrs.push(IRLInstruction::Mv {
|
instrs.push(IRLInstruction::Mv {
|
||||||
dest: *dest,
|
dest: dest.id,
|
||||||
src: *src,
|
src: src.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IRUInstruction::Ref { dest, src } => {
|
IRUInstruction::Ref { dest, src } => {
|
||||||
if alloc_stack(dest) {
|
if alloc_stack(dest.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
instrs.push(IRLInstruction::Ref {
|
instrs.push(IRLInstruction::Ref {
|
||||||
dest: *dest,
|
dest: dest.id,
|
||||||
src: *src,
|
src: src.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IRUInstruction::LoadData { dest, src } => {
|
IRUInstruction::LoadData { dest, src } => {
|
||||||
if alloc_stack(dest) {
|
if alloc_stack(dest.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let data = &ns.data[src.0];
|
let data = &p.data[src.0];
|
||||||
let sym = builder.ro_data(src, data);
|
let sym = builder.ro_data(src, data);
|
||||||
instrs.push(IRLInstruction::LoadData {
|
instrs.push(IRLInstruction::LoadData {
|
||||||
dest: *dest,
|
dest: dest.id,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
len: data.len() as Len,
|
len: data.len() as Len,
|
||||||
src: sym,
|
src: sym,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IRUInstruction::LoadSlice { dest, src, len } => {
|
IRUInstruction::LoadSlice { dest, src } => {
|
||||||
if alloc_stack(dest) {
|
if alloc_stack(dest.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let sym = builder.ro_data(src, &ns.data[src.0]);
|
let data = &p.data[src.0];
|
||||||
|
let def = p.get_data(*src);
|
||||||
|
let Type::Array(ty, len) = &def.ty else {
|
||||||
|
return Err(format!("tried to load {} as slice", p.type_name(&def.ty)));
|
||||||
|
};
|
||||||
|
let sym = builder.ro_data(src, data);
|
||||||
instrs.push(IRLInstruction::LoadAddr {
|
instrs.push(IRLInstruction::LoadAddr {
|
||||||
dest: *dest,
|
dest: dest.id,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
src: sym,
|
src: sym,
|
||||||
});
|
});
|
||||||
|
|
||||||
let sym = builder.anon_ro_data(&(*len as u64).to_le_bytes());
|
let sym = builder.anon_ro_data(&(*len as u64).to_le_bytes());
|
||||||
instrs.push(IRLInstruction::LoadData {
|
instrs.push(IRLInstruction::LoadData {
|
||||||
dest: *dest,
|
dest: dest.id,
|
||||||
offset: 8,
|
offset: 8,
|
||||||
len: 8,
|
len: 8,
|
||||||
src: sym,
|
src: sym,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IRUInstruction::LoadFn { dest, src } => {
|
IRUInstruction::LoadFn { dest, src } => {
|
||||||
if alloc_stack(dest) {
|
if alloc_stack(dest.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let sym = builder.func(src);
|
let sym = builder.func(src);
|
||||||
instrs.push(IRLInstruction::LoadAddr {
|
instrs.push(IRLInstruction::LoadAddr {
|
||||||
dest: *dest,
|
dest: dest.id,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
src: sym,
|
src: sym,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IRUInstruction::Call { dest, f, args } => {
|
IRUInstruction::Call { dest, f, args } => {
|
||||||
alloc_stack(dest);
|
alloc_stack(dest.id);
|
||||||
makes_call = true;
|
makes_call = true;
|
||||||
let fid = &ns.fn_map[f];
|
let fid = &p.fn_map[&f.id];
|
||||||
let sym = builder.func(fid);
|
let sym = builder.func(fid);
|
||||||
instrs.push(IRLInstruction::Call {
|
instrs.push(IRLInstruction::Call {
|
||||||
dest: *dest,
|
dest: dest.id,
|
||||||
f: sym,
|
f: sym,
|
||||||
args: args
|
args: args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| (*a, ns.size_of_var(a).expect("unsized type")))
|
.map(|a| (a.id, p.size_of_var(a.id).expect("unsized type")))
|
||||||
.collect(),
|
.collect(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IRUInstruction::AsmBlock { instructions, args } => {
|
IRUInstruction::AsmBlock { instructions, args } => {
|
||||||
instrs.push(IRLInstruction::AsmBlock {
|
instrs.push(IRLInstruction::AsmBlock {
|
||||||
instructions: instructions.clone(),
|
instructions: instructions.clone(),
|
||||||
args: args.clone(),
|
args: args.iter().cloned().map(|(r, v)| (r, v.id)).collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
IRUInstruction::Ret { src } => instrs.push(IRLInstruction::Ret { src: *src }),
|
IRUInstruction::Ret { src } => instrs.push(IRLInstruction::Ret { src: src.id }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
builder.write_fn(
|
builder.write_fn(
|
||||||
@@ -127,7 +133,7 @@ impl IRLProgram {
|
|||||||
args: f
|
args: f
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| (*a, ns.size_of_var(a).expect("unsized type")))
|
.map(|a| (*a, p.size_of_var(*a).expect("unsized type")))
|
||||||
.collect(),
|
.collect(),
|
||||||
stack,
|
stack,
|
||||||
},
|
},
|
||||||
@@ -139,7 +145,7 @@ impl IRLProgram {
|
|||||||
// println!(" {:?}: {}", a, f.name);
|
// println!(" {:?}: {}", a, f.name);
|
||||||
// }
|
// }
|
||||||
// println!("datas: {}", sym_space.ro_data().len());
|
// println!("datas: {}", sym_space.ro_data().len());
|
||||||
Some(Self { sym_space, entry })
|
Ok(Self { sym_space, entry })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry(&self) -> Symbol {
|
pub fn entry(&self) -> Symbol {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
mod upper;
|
mod upper;
|
||||||
mod file;
|
|
||||||
mod lower;
|
mod lower;
|
||||||
mod id;
|
mod id;
|
||||||
mod asm;
|
mod asm;
|
||||||
@@ -7,5 +6,4 @@ pub mod arch;
|
|||||||
|
|
||||||
pub use upper::*;
|
pub use upper::*;
|
||||||
pub use lower::*;
|
pub use lower::*;
|
||||||
pub use file::*;
|
|
||||||
pub use id::*;
|
pub use id::*;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use super::{FileSpan, Type};
|
use crate::common::FileSpan;
|
||||||
|
|
||||||
|
use super::Type;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -23,6 +25,12 @@ pub struct VarDef {
|
|||||||
pub origin: Origin,
|
pub origin: Origin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DataDef {
|
||||||
|
pub ty: Type,
|
||||||
|
pub origin: Origin,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Origin {
|
pub enum Origin {
|
||||||
Builtin,
|
Builtin,
|
||||||
|
|||||||
19
src/ir/upper/error.rs
Normal file
19
src/ir/upper/error.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||||
|
|
||||||
|
use super::{IRUProgram, Type};
|
||||||
|
|
||||||
|
impl CompilerOutput {
|
||||||
|
pub fn check_assign(&mut self, p: &IRUProgram, src: &Type, dest: &Type, span: FileSpan) {
|
||||||
|
// TODO: spans
|
||||||
|
if src != dest {
|
||||||
|
self.err(CompilerMsg {
|
||||||
|
msg: format!(
|
||||||
|
"Cannot assign type '{}' to '{}'",
|
||||||
|
p.type_name(src),
|
||||||
|
p.type_name(dest)
|
||||||
|
),
|
||||||
|
spans: vec![span],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,52 +1,51 @@
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use super::{arch::riscv64::RV64Instruction, DataID, FnID, Len, VarID};
|
use super::{arch::riscv64::RV64Instruction, inst::VarInst, DataID, FnID, IRUInstrInst, VarID};
|
||||||
use crate::{compiler::arch::riscv64::Reg, util::Padder};
|
use crate::{common::FileSpan, compiler::arch::riscv64::Reg, util::Padder};
|
||||||
|
|
||||||
pub struct IRUFunction {
|
pub struct IRUFunction {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub args: Vec<VarID>,
|
pub args: Vec<VarID>,
|
||||||
pub instructions: Vec<IRUInstruction>,
|
pub instructions: Vec<IRUInstrInst>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum IRUInstruction {
|
pub enum IRUInstruction {
|
||||||
Mv {
|
Mv {
|
||||||
dest: VarID,
|
dest: VarInst,
|
||||||
src: VarID,
|
src: VarInst,
|
||||||
},
|
},
|
||||||
Ref {
|
Ref {
|
||||||
dest: VarID,
|
dest: VarInst,
|
||||||
src: VarID,
|
src: VarInst,
|
||||||
},
|
},
|
||||||
LoadData {
|
LoadData {
|
||||||
dest: VarID,
|
dest: VarInst,
|
||||||
src: DataID,
|
src: DataID,
|
||||||
},
|
},
|
||||||
LoadSlice {
|
LoadSlice {
|
||||||
dest: VarID,
|
dest: VarInst,
|
||||||
src: DataID,
|
src: DataID,
|
||||||
len: Len,
|
|
||||||
},
|
},
|
||||||
LoadFn {
|
LoadFn {
|
||||||
dest: VarID,
|
dest: VarInst,
|
||||||
src: FnID,
|
src: FnID,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
dest: VarID,
|
dest: VarInst,
|
||||||
f: VarID,
|
f: VarInst,
|
||||||
args: Vec<VarID>,
|
args: Vec<VarInst>,
|
||||||
},
|
},
|
||||||
AsmBlock {
|
AsmBlock {
|
||||||
instructions: Vec<RV64Instruction>,
|
instructions: Vec<RV64Instruction>,
|
||||||
args: Vec<(Reg, VarID)>,
|
args: Vec<(Reg, VarInst)>,
|
||||||
},
|
},
|
||||||
Ret {
|
Ret {
|
||||||
src: VarID,
|
src: VarInst,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IRInstructions {
|
pub struct IRInstructions {
|
||||||
vec: Vec<IRUInstruction>,
|
vec: Vec<IRUInstrInst>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IRUFunction {
|
impl IRUFunction {
|
||||||
@@ -63,8 +62,8 @@ impl IRInstructions {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { vec: Vec::new() }
|
Self { vec: Vec::new() }
|
||||||
}
|
}
|
||||||
pub fn push(&mut self, i: IRUInstruction) {
|
pub fn push(&mut self, i: IRUInstruction, span: FileSpan) {
|
||||||
self.vec.push(i);
|
self.vec.push(IRUInstrInst { i, span });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +74,7 @@ impl std::fmt::Debug for IRUInstruction {
|
|||||||
Self::Ref { dest, src } => write!(f, "{dest:?} <- &{src:?}"),
|
Self::Ref { dest, src } => write!(f, "{dest:?} <- &{src:?}"),
|
||||||
Self::LoadData { dest, src } => write!(f, "{dest:?} <- {src:?}"),
|
Self::LoadData { dest, src } => write!(f, "{dest:?} <- {src:?}"),
|
||||||
Self::LoadFn { dest, src } => write!(f, "{dest:?} <- {src:?}"),
|
Self::LoadFn { dest, src } => write!(f, "{dest:?} <- {src:?}"),
|
||||||
Self::LoadSlice { dest, src, len } => write!(f, "{dest:?} <- &[{src:?}; {len}]"),
|
Self::LoadSlice { dest, src } => write!(f, "{dest:?} <- &[{src:?}]"),
|
||||||
Self::Call {
|
Self::Call {
|
||||||
dest,
|
dest,
|
||||||
f: func,
|
f: func,
|
||||||
|
|||||||
27
src/ir/upper/inst.rs
Normal file
27
src/ir/upper/inst.rs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
use crate::{common::FileSpan, ir::VarID};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use super::IRUInstruction;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct VarInst {
|
||||||
|
pub id: VarID,
|
||||||
|
pub span: FileSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IRUInstrInst {
|
||||||
|
pub i: IRUInstruction,
|
||||||
|
pub span: FileSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for VarInst {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?}", self.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for IRUInstrInst {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?}", self.i)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
mod def;
|
mod def;
|
||||||
mod func;
|
mod func;
|
||||||
mod ty;
|
mod ty;
|
||||||
mod namespace;
|
mod program;
|
||||||
|
mod validate;
|
||||||
|
mod error;
|
||||||
|
mod inst;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
pub use def::*;
|
pub use def::*;
|
||||||
pub use func::*;
|
pub use func::*;
|
||||||
pub use ty::*;
|
pub use ty::*;
|
||||||
pub use namespace::*;
|
pub use program::*;
|
||||||
|
pub use inst::*;
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ use std::{
|
|||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use crate::common::FileSpan;
|
||||||
|
|
||||||
pub struct Namespace {
|
use super::{inst::VarInst, *};
|
||||||
|
|
||||||
|
pub struct IRUProgram {
|
||||||
pub fn_defs: Vec<FnDef>,
|
pub fn_defs: Vec<FnDef>,
|
||||||
pub var_defs: Vec<VarDef>,
|
pub var_defs: Vec<VarDef>,
|
||||||
pub type_defs: Vec<TypeDef>,
|
pub type_defs: Vec<TypeDef>,
|
||||||
|
pub data_defs: Vec<DataDef>,
|
||||||
pub fns: Vec<Option<IRUFunction>>,
|
pub fns: Vec<Option<IRUFunction>>,
|
||||||
pub data: Vec<Vec<u8>>,
|
pub data: Vec<Vec<u8>>,
|
||||||
pub fn_map: HashMap<VarID, FnID>,
|
pub fn_map: HashMap<VarID, FnID>,
|
||||||
@@ -17,12 +20,13 @@ pub struct Namespace {
|
|||||||
pub stack: Vec<HashMap<String, Idents>>,
|
pub stack: Vec<HashMap<String, Idents>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Namespace {
|
impl IRUProgram {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
fn_defs: Vec::new(),
|
fn_defs: Vec::new(),
|
||||||
var_defs: Vec::new(),
|
var_defs: Vec::new(),
|
||||||
type_defs: Vec::new(),
|
type_defs: Vec::new(),
|
||||||
|
data_defs: Vec::new(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
fn_map: HashMap::new(),
|
fn_map: HashMap::new(),
|
||||||
fns: Vec::new(),
|
fns: Vec::new(),
|
||||||
@@ -49,6 +53,9 @@ impl Namespace {
|
|||||||
pub fn get_fn(&self, id: FnID) -> &FnDef {
|
pub fn get_fn(&self, id: FnID) -> &FnDef {
|
||||||
&self.fn_defs[id.0]
|
&self.fn_defs[id.0]
|
||||||
}
|
}
|
||||||
|
pub fn get_data(&self, id: DataID) -> &DataDef {
|
||||||
|
&self.data_defs[id.0]
|
||||||
|
}
|
||||||
pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> {
|
pub fn get_fn_var(&self, id: VarID) -> Option<&FnDef> {
|
||||||
Some(&self.fn_defs[self.fn_map.get(&id)?.0])
|
Some(&self.fn_defs[self.fn_map.get(&id)?.0])
|
||||||
}
|
}
|
||||||
@@ -90,17 +97,20 @@ impl Namespace {
|
|||||||
Type::Unit => 0,
|
Type::Unit => 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn size_of_var(&self, var: &VarID) -> Option<Size> {
|
pub fn size_of_var(&self, var: VarID) -> Option<Size> {
|
||||||
self.size_of_type(&self.var_defs[var.0].ty)
|
self.size_of_type(&self.var_defs[var.0].ty)
|
||||||
}
|
}
|
||||||
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarID {
|
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarInst {
|
||||||
let v = self.def_var(VarDef {
|
let v = self.def_var(VarDef {
|
||||||
name: format!("temp{}", self.temp),
|
name: format!("temp{}", self.temp),
|
||||||
origin: super::Origin::File(origin),
|
origin: super::Origin::File(origin),
|
||||||
ty,
|
ty,
|
||||||
});
|
});
|
||||||
self.temp += 1;
|
self.temp += 1;
|
||||||
v
|
VarInst {
|
||||||
|
id: v,
|
||||||
|
span: origin,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn def_fn(&mut self, def: FnDef) -> FnID {
|
pub fn def_fn(&mut self, def: FnDef) -> FnID {
|
||||||
let i = self.fn_defs.len();
|
let i = self.fn_defs.len();
|
||||||
@@ -128,8 +138,9 @@ impl Namespace {
|
|||||||
self.type_defs.push(def);
|
self.type_defs.push(def);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
pub fn def_data(&mut self, bytes: Vec<u8>) -> DataID {
|
pub fn def_data(&mut self, def: DataDef, bytes: Vec<u8>) -> DataID {
|
||||||
let i = self.data.len();
|
let i = self.data.len();
|
||||||
|
self.data_defs.push(def);
|
||||||
self.data.push(bytes);
|
self.data.push(bytes);
|
||||||
DataID(i)
|
DataID(i)
|
||||||
}
|
}
|
||||||
@@ -187,18 +198,17 @@ impl Namespace {
|
|||||||
self.fns[id.0] = Some(f);
|
self.fns[id.0] = Some(f);
|
||||||
}
|
}
|
||||||
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &VarDef)> {
|
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &VarDef)> {
|
||||||
(0..self.var_defs.len())
|
self.var_defs.iter().enumerate().map(|(i, v)| (VarID(i), v))
|
||||||
.map(|i| VarID(i))
|
|
||||||
.zip(self.var_defs.iter())
|
|
||||||
}
|
}
|
||||||
pub fn iter_fns(&self) -> impl Iterator<Item = (FnID, Option<&IRUFunction>)> {
|
pub fn iter_fns(&self) -> impl Iterator<Item = (FnID, &IRUFunction)> {
|
||||||
(0..self.fns.len())
|
self.fns
|
||||||
.map(|i| FnID(i))
|
.iter()
|
||||||
.zip(self.fns.iter().map(|f| f.as_ref()))
|
.enumerate()
|
||||||
|
.flat_map(|(i, f)| Some((FnID(i), f.as_ref()?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NamespaceGuard<'a>(&'a mut Namespace);
|
pub struct NamespaceGuard<'a>(&'a mut IRUProgram);
|
||||||
|
|
||||||
impl Drop for NamespaceGuard<'_> {
|
impl Drop for NamespaceGuard<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
@@ -207,7 +217,7 @@ impl Drop for NamespaceGuard<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for NamespaceGuard<'_> {
|
impl Deref for NamespaceGuard<'_> {
|
||||||
type Target = Namespace;
|
type Target = IRUProgram;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::{Len, TypeID};
|
use super::{IRUInstruction, IRUProgram, Len, TypeID};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Concrete(TypeID),
|
Concrete(TypeID),
|
||||||
Bits(u32),
|
Bits(u32),
|
||||||
@@ -25,3 +25,20 @@ impl Type {
|
|||||||
Self::Slice(Box::new(self))
|
Self::Slice(Box::new(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn resolve_types(ns: &IRUProgram) {
|
||||||
|
for (i, f) in ns.iter_fns() {
|
||||||
|
for inst in &f.instructions {
|
||||||
|
match &inst.i {
|
||||||
|
IRUInstruction::Mv { dest, src } => todo!(),
|
||||||
|
IRUInstruction::Ref { dest, src } => todo!(),
|
||||||
|
IRUInstruction::LoadData { dest, src } => todo!(),
|
||||||
|
IRUInstruction::LoadSlice { dest, src } => todo!(),
|
||||||
|
IRUInstruction::LoadFn { dest, src } => todo!(),
|
||||||
|
IRUInstruction::Call { dest, f, args } => todo!(),
|
||||||
|
IRUInstruction::AsmBlock { instructions, args } => todo!(),
|
||||||
|
IRUInstruction::Ret { src } => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
52
src/ir/upper/validate.rs
Normal file
52
src/ir/upper/validate.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// TODO: move this into ir, not parser
|
||||||
|
use super::{IRUProgram, Type};
|
||||||
|
use crate::common::CompilerOutput;
|
||||||
|
|
||||||
|
impl IRUProgram {
|
||||||
|
pub fn validate(&self) -> CompilerOutput {
|
||||||
|
let mut output = CompilerOutput::new();
|
||||||
|
for f in self.fns.iter().flatten() {
|
||||||
|
for i in &f.instructions {
|
||||||
|
match &i.i {
|
||||||
|
super::IRUInstruction::Mv { dest, src } => {
|
||||||
|
let dest = self.get_var(dest.id);
|
||||||
|
let src = self.get_var(src.id);
|
||||||
|
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||||
|
}
|
||||||
|
super::IRUInstruction::Ref { dest, src } => todo!(),
|
||||||
|
super::IRUInstruction::LoadData { dest, src } => {
|
||||||
|
let dest = self.get_var(dest.id);
|
||||||
|
let src = self.get_data(*src);
|
||||||
|
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||||
|
}
|
||||||
|
super::IRUInstruction::LoadSlice { dest, src } => {
|
||||||
|
let dest = self.get_var(dest.id);
|
||||||
|
let src = self.get_data(*src);
|
||||||
|
let Type::Array(srcty, ..) = &src.ty else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
output.check_assign(self, &Type::Slice(srcty.clone()), &dest.ty, i.span);
|
||||||
|
}
|
||||||
|
super::IRUInstruction::LoadFn { dest, src } => todo!(),
|
||||||
|
super::IRUInstruction::Call { dest, f, args } => {
|
||||||
|
let destty = &self.get_var(dest.id).ty;
|
||||||
|
let f = self.get_var(f.id);
|
||||||
|
let Type::Fn { args: argtys, ret } = &f.ty else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
output.check_assign(self, ret, destty, dest.span);
|
||||||
|
for (argv, argt) in args.iter().zip(argtys) {
|
||||||
|
let dest = self.get_var(argv.id);
|
||||||
|
output.check_assign(self, argt, &dest.ty, argv.span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super::IRUInstruction::AsmBlock { instructions, args } => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
super::IRUInstruction::Ret { src } => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main.rs
18
src/main.rs
@@ -1,7 +1,7 @@
|
|||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(try_trait_v2)]
|
#![feature(try_trait_v2)]
|
||||||
|
|
||||||
use ir::{Namespace, IRLProgram};
|
use ir::{IRLProgram, IRUProgram};
|
||||||
use parser::{NodeParsable, PModule, PStatement, ParserCtx};
|
use parser::{NodeParsable, PModule, PStatement, ParserCtx};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{create_dir_all, OpenOptions},
|
fs::{create_dir_all, OpenOptions},
|
||||||
@@ -11,10 +11,12 @@ use std::{
|
|||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod common;
|
||||||
mod compiler;
|
mod compiler;
|
||||||
mod ir;
|
mod ir;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod util;
|
mod util;
|
||||||
|
use common::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let file = std::env::args_os().nth(1);
|
let file = std::env::args_os().nth(1);
|
||||||
@@ -34,7 +36,7 @@ fn run_file(file: &str, gdb: bool) {
|
|||||||
// println!("Parsed:");
|
// println!("Parsed:");
|
||||||
// println!("{:#?}", res.node);
|
// println!("{:#?}", res.node);
|
||||||
if let Some(module) = res.node.as_ref() {
|
if let Some(module) = res.node.as_ref() {
|
||||||
let mut namespace = Namespace::new();
|
let mut namespace = IRUProgram::new();
|
||||||
module.lower(&mut namespace.push(), &mut ctx.output);
|
module.lower(&mut namespace.push(), &mut ctx.output);
|
||||||
if ctx.output.errs.is_empty() {
|
if ctx.output.errs.is_empty() {
|
||||||
// println!("vars:");
|
// println!("vars:");
|
||||||
@@ -44,10 +46,14 @@ fn run_file(file: &str, gdb: bool) {
|
|||||||
// for (id, f) in namespace.iter_fns() {
|
// for (id, f) in namespace.iter_fns() {
|
||||||
// println!("{id:?} = {:#?}", f.unwrap());
|
// println!("{id:?} = {:#?}", f.unwrap());
|
||||||
// }
|
// }
|
||||||
let program = IRLProgram::create(&namespace);
|
let output = namespace.validate();
|
||||||
let bin = compiler::compile(program.expect("morir"));
|
output.write_for(&mut stdout(), file);
|
||||||
println!("compiled");
|
if output.errs.is_empty() {
|
||||||
save_run(&bin, gdb);
|
let program = IRLProgram::create(&namespace);
|
||||||
|
let bin = compiler::compile(program.expect("morir"));
|
||||||
|
println!("compiled");
|
||||||
|
save_run(&bin, gdb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use super::{MaybeParsable, Node, NodeParseResult, Parsable, ParserMsg, ParserOutput, TokenCursor};
|
use super::{
|
||||||
|
MaybeParsable, Node, NodeParseResult, Parsable, ParsableWith, CompilerMsg, CompilerOutput,
|
||||||
|
TokenCursor,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct ParserCtx<'a> {
|
pub struct ParserCtx<'a> {
|
||||||
pub cursor: TokenCursor<'a>,
|
pub cursor: TokenCursor<'a>,
|
||||||
pub output: ParserOutput,
|
pub output: CompilerOutput,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deref for ParserCtx<'a> {
|
impl<'a> Deref for ParserCtx<'a> {
|
||||||
@@ -22,15 +25,18 @@ impl DerefMut for ParserCtx<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ParserCtx<'a> {
|
impl<'a> ParserCtx<'a> {
|
||||||
pub fn err(&mut self, msg: ParserMsg) {
|
pub fn err(&mut self, msg: CompilerMsg) {
|
||||||
self.output.err(msg);
|
self.output.err(msg);
|
||||||
}
|
}
|
||||||
pub fn hint(&mut self, msg: ParserMsg) {
|
pub fn hint(&mut self, msg: CompilerMsg) {
|
||||||
self.output.hint(msg);
|
self.output.hint(msg);
|
||||||
}
|
}
|
||||||
pub fn parse<T: Parsable>(&mut self) -> NodeParseResult<T> {
|
pub fn parse<T: Parsable>(&mut self) -> NodeParseResult<T> {
|
||||||
Node::parse(self)
|
Node::parse(self)
|
||||||
}
|
}
|
||||||
|
pub fn parse_with<T: ParsableWith>(&mut self, data: T::Data) -> NodeParseResult<T> {
|
||||||
|
Node::parse_with(self, data)
|
||||||
|
}
|
||||||
pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> {
|
pub fn maybe_parse<T: MaybeParsable>(&mut self) -> Option<Node<T>> {
|
||||||
Node::maybe_parse(self)
|
Node::maybe_parse(self)
|
||||||
}
|
}
|
||||||
@@ -40,7 +46,7 @@ impl<'a> From<TokenCursor<'a>> for ParserCtx<'a> {
|
|||||||
fn from(cursor: TokenCursor<'a>) -> Self {
|
fn from(cursor: TokenCursor<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cursor,
|
cursor,
|
||||||
output: ParserOutput::new(),
|
output: CompilerOutput::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,7 +55,7 @@ impl<'a> From<&'a str> for ParserCtx<'a> {
|
|||||||
fn from(string: &'a str) -> Self {
|
fn from(string: &'a str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cursor: TokenCursor::from(string),
|
cursor: TokenCursor::from(string),
|
||||||
output: ParserOutput::new(),
|
output: CompilerOutput::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::ir::FilePos;
|
use super::{
|
||||||
|
token::{CharCursor, Keyword, Symbol, Token, TokenInstance},
|
||||||
use super::error::ParserMsg;
|
CompilerMsg, FilePos,
|
||||||
use super::token::{CharCursor, Keyword, Symbol, Token, TokenInstance};
|
};
|
||||||
|
|
||||||
pub struct TokenCursor<'a> {
|
pub struct TokenCursor<'a> {
|
||||||
cursor: CharCursor<'a>,
|
cursor: CharCursor<'a>,
|
||||||
@@ -12,11 +12,7 @@ pub struct TokenCursor<'a> {
|
|||||||
|
|
||||||
impl<'a> TokenCursor<'a> {
|
impl<'a> TokenCursor<'a> {
|
||||||
pub fn next(&mut self) -> Option<TokenInstance> {
|
pub fn next(&mut self) -> Option<TokenInstance> {
|
||||||
self.prev_end = self
|
self.prev_end = self.cursor.prev_pos();
|
||||||
.next
|
|
||||||
.as_ref()
|
|
||||||
.map(|i| i.span.end)
|
|
||||||
.unwrap_or(FilePos::start());
|
|
||||||
let next = TokenInstance::parse(&mut self.cursor);
|
let next = TokenInstance::parse(&mut self.cursor);
|
||||||
self.next_start = next
|
self.next_start = next
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -24,19 +20,19 @@ impl<'a> TokenCursor<'a> {
|
|||||||
.unwrap_or(FilePos::start());
|
.unwrap_or(FilePos::start());
|
||||||
std::mem::replace(&mut self.next, next)
|
std::mem::replace(&mut self.next, next)
|
||||||
}
|
}
|
||||||
pub fn expect_next(&mut self) -> Result<TokenInstance, ParserMsg> {
|
pub fn expect_next(&mut self) -> Result<TokenInstance, CompilerMsg> {
|
||||||
self.peek().ok_or(ParserMsg::unexpected_end())?;
|
self.peek().ok_or(CompilerMsg::unexpected_end())?;
|
||||||
Ok(self.next().unwrap())
|
Ok(self.next().unwrap())
|
||||||
}
|
}
|
||||||
pub fn expect_token(&mut self, t: Token) -> Result<(), ParserMsg> {
|
pub fn expect_token(&mut self, t: Token) -> Result<(), CompilerMsg> {
|
||||||
let next = self.expect_next()?;
|
let next = self.expect_next()?;
|
||||||
if t == next.token {
|
if t == next.token {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ParserMsg::unexpected_token(&next, &format!("{t:?}")))
|
Err(CompilerMsg::unexpected_token(&next, &format!("{t:?}")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), ParserMsg> {
|
pub fn expect_sym(&mut self, symbol: Symbol) -> Result<(), CompilerMsg> {
|
||||||
self.expect_token(Token::Symbol(symbol))
|
self.expect_token(Token::Symbol(symbol))
|
||||||
}
|
}
|
||||||
pub fn next_on_new_line(&mut self) -> bool {
|
pub fn next_on_new_line(&mut self) -> bool {
|
||||||
@@ -64,14 +60,14 @@ impl<'a> TokenCursor<'a> {
|
|||||||
self.next();
|
self.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), ParserMsg> {
|
pub fn expect_kw(&mut self, kw: Keyword) -> Result<(), CompilerMsg> {
|
||||||
self.expect_token(Token::Keyword(kw))
|
self.expect_token(Token::Keyword(kw))
|
||||||
}
|
}
|
||||||
pub fn peek(&self) -> Option<&TokenInstance> {
|
pub fn peek(&self) -> Option<&TokenInstance> {
|
||||||
self.next.as_ref()
|
self.next.as_ref()
|
||||||
}
|
}
|
||||||
pub fn expect_peek(&mut self) -> Result<&TokenInstance, ParserMsg> {
|
pub fn expect_peek(&mut self) -> Result<&TokenInstance, CompilerMsg> {
|
||||||
self.peek().ok_or(ParserMsg::unexpected_end())
|
self.peek().ok_or(CompilerMsg::unexpected_end())
|
||||||
}
|
}
|
||||||
pub fn chars(&mut self) -> &mut CharCursor<'a> {
|
pub fn chars(&mut self) -> &mut CharCursor<'a> {
|
||||||
&mut self.cursor
|
&mut self.cursor
|
||||||
|
|||||||
@@ -1,36 +1,17 @@
|
|||||||
use crate::ir::{FilePos, FileSpan};
|
use super::Node;
|
||||||
|
use super::PIdent;
|
||||||
|
use super::CompilerMsg;
|
||||||
|
use super::TokenInstance;
|
||||||
|
|
||||||
use super::{token::TokenInstance, PIdent, Node};
|
impl CompilerMsg {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ParserMsg {
|
|
||||||
pub msg: String,
|
|
||||||
pub spans: Vec<FileSpan>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ParserOutput {
|
|
||||||
pub errs: Vec<ParserMsg>,
|
|
||||||
pub hints: Vec<ParserMsg>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParserMsg {
|
|
||||||
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
|
pub fn from_instances(instances: &[&TokenInstance], msg: String) -> Self {
|
||||||
ParserMsg {
|
CompilerMsg {
|
||||||
msg,
|
msg,
|
||||||
spans: instances.iter().map(|i| i.span).collect(),
|
spans: instances.iter().map(|i| i.span).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_msg(msg: String) -> Self {
|
pub fn unexpected_end() -> Self {
|
||||||
Self {
|
Self::from_msg("unexpected end of input".to_string())
|
||||||
msg,
|
|
||||||
spans: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn from_span(span: FileSpan, msg: String) -> Self {
|
|
||||||
Self {
|
|
||||||
msg,
|
|
||||||
spans: vec![span],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn identifier_not_found(id: &Node<PIdent>) -> Self {
|
pub fn identifier_not_found(id: &Node<PIdent>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -38,51 +19,11 @@ impl ParserMsg {
|
|||||||
spans: vec![id.span],
|
spans: vec![id.span],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn at(pos: FilePos, msg: String) -> Self {
|
|
||||||
Self {
|
|
||||||
msg,
|
|
||||||
spans: vec![FileSpan::at(pos)],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn unexpected_end() -> Self {
|
|
||||||
Self::from_msg("unexpected end of input".to_string())
|
|
||||||
}
|
|
||||||
pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self {
|
pub fn unexpected_token(inst: &TokenInstance, expected: &str) -> Self {
|
||||||
let t = &inst.token;
|
let t = &inst.token;
|
||||||
ParserMsg::from_instances(
|
CompilerMsg::from_instances(
|
||||||
&[inst],
|
&[inst],
|
||||||
format!("unexpected token {t:?}; expected {expected}"),
|
format!("unexpected token {t:?}; expected {expected}"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pub fn write_for(&self, ty: &str, writer: &mut impl std::io::Write, file: &str) -> std::io::Result<()> {
|
|
||||||
let after = if self.spans.is_empty() { "" } else { ":" };
|
|
||||||
writeln!(writer, "{}: {}{}", ty, self.msg, after)?;
|
|
||||||
for span in &self.spans {
|
|
||||||
span.write_for(writer, file)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParserOutput {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
errs: Vec::new(),
|
|
||||||
hints: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn err(&mut self, msg: ParserMsg) {
|
|
||||||
self.errs.push(msg);
|
|
||||||
}
|
|
||||||
pub fn hint(&mut self, msg: ParserMsg) {
|
|
||||||
self.hints.push(msg);
|
|
||||||
}
|
|
||||||
pub fn write_for(&self, out: &mut impl std::io::Write, file: &str) {
|
|
||||||
for err in &self.errs {
|
|
||||||
err.write_for("error", out, file).unwrap();
|
|
||||||
}
|
|
||||||
for hint in &self.hints {
|
|
||||||
hint.write_for("hint", out, file).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::{
|
|||||||
compiler::arch::riscv64::*,
|
compiler::arch::riscv64::*,
|
||||||
ir::{
|
ir::{
|
||||||
arch::riscv64::{RV64Instruction, RegRef},
|
arch::riscv64::{RV64Instruction, RegRef},
|
||||||
VarID,
|
VarInst,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ impl RV64Instruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
pub fn arg_to_var(node: &Node<PAsmArg>, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||||
let PAsmArg::Ref(node) = node.inner.as_ref()? else {
|
let PAsmArg::Ref(node) = node.inner.as_ref()? else {
|
||||||
ctx.err_at(
|
ctx.err_at(
|
||||||
node.span,
|
node.span,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
compiler::arch::riscv64::Reg,
|
compiler::arch::riscv64::Reg,
|
||||||
ir::{arch::riscv64::RV64Instruction, IRUInstruction, VarID},
|
ir::{arch::riscv64::RV64Instruction, IRUInstruction, VarInst},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{PAsmBlock, PAsmBlockArg, FnLowerCtx, FnLowerable, PInstruction};
|
use super::{FnLowerCtx, FnLowerable, PAsmBlock, PAsmBlockArg, PInstruction};
|
||||||
|
|
||||||
impl FnLowerable for PInstruction {
|
impl FnLowerable for PInstruction {
|
||||||
type Output = RV64Instruction;
|
type Output = RV64Instruction;
|
||||||
@@ -43,7 +43,7 @@ impl FnLowerable for PAsmBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FnLowerable for PAsmBlockArg {
|
impl FnLowerable for PAsmBlockArg {
|
||||||
type Output = (Reg, VarID);
|
type Output = (Reg, VarInst);
|
||||||
|
|
||||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
|
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
|
||||||
let var = ctx.get_var(&self.var)?;
|
let var = ctx.get_var(&self.var)?;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::ir::{IRUInstruction, VarID};
|
use crate::ir::{IRUInstruction, VarInst};
|
||||||
|
|
||||||
use super::{PBlock, FnLowerCtx, FnLowerable, PStatement};
|
use super::{FnLowerCtx, FnLowerable, PBlock, PStatement};
|
||||||
|
|
||||||
impl FnLowerable for PBlock {
|
impl FnLowerable for PBlock {
|
||||||
type Output = VarID;
|
type Output = VarInst;
|
||||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||||
let ctx = &mut ctx.sub();
|
let ctx = &mut ctx.sub();
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.lower(ctx);
|
statement.lower(ctx);
|
||||||
@@ -14,20 +14,20 @@ impl FnLowerable for PBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FnLowerable for PStatement {
|
impl FnLowerable for PStatement {
|
||||||
type Output = VarID;
|
type Output = VarInst;
|
||||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||||
match self {
|
match self {
|
||||||
super::PStatement::Let(def, e) => {
|
super::PStatement::Let(def, e) => {
|
||||||
let def = def.lower(ctx.map, ctx.output)?;
|
let def = def.lower(ctx.map, ctx.output)?;
|
||||||
let res = e.lower(ctx);
|
let res = e.lower(ctx);
|
||||||
if let Some(res) = res {
|
if let Some(res) = res {
|
||||||
ctx.map.name_var(&def, res);
|
ctx.map.name_var(&def, res.id);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
super::PStatement::Return(e) => {
|
super::PStatement::Return(e) => {
|
||||||
let src = e.lower(ctx)?;
|
let src = e.lower(ctx)?;
|
||||||
ctx.push(IRUInstruction::Ret { src });
|
ctx.push_at(IRUInstruction::Ret { src }, src.span);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
super::PStatement::Expr(e) => e.lower(ctx),
|
super::PStatement::Expr(e) => e.lower(ctx),
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use crate::ir::{FileSpan, NamespaceGuard, Origin, Type, VarDef};
|
use crate::ir::{NamespaceGuard, Origin, Type, VarDef};
|
||||||
|
|
||||||
use super::{Node, PType, PVarDef, ParserMsg, ParserOutput};
|
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef};
|
||||||
|
|
||||||
impl Node<PVarDef> {
|
impl Node<PVarDef> {
|
||||||
pub fn lower(
|
pub fn lower(
|
||||||
&self,
|
&self,
|
||||||
namespace: &mut NamespaceGuard,
|
namespace: &mut NamespaceGuard,
|
||||||
output: &mut ParserOutput,
|
output: &mut CompilerOutput,
|
||||||
) -> Option<VarDef> {
|
) -> Option<VarDef> {
|
||||||
let s = self.as_ref()?;
|
let s = self.as_ref()?;
|
||||||
let name = s.name.as_ref()?.to_string();
|
let name = s.name.as_ref()?.to_string();
|
||||||
@@ -23,7 +23,7 @@ impl Node<PVarDef> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Node<PType> {
|
impl Node<PType> {
|
||||||
pub fn lower(&self, namespace: &mut NamespaceGuard, output: &mut ParserOutput) -> Type {
|
pub fn lower(&self, namespace: &mut NamespaceGuard, output: &mut CompilerOutput) -> Type {
|
||||||
self.as_ref()
|
self.as_ref()
|
||||||
.map(|t| t.lower(namespace, output, self.span))
|
.map(|t| t.lower(namespace, output, self.span))
|
||||||
.unwrap_or(Type::Error)
|
.unwrap_or(Type::Error)
|
||||||
@@ -34,7 +34,7 @@ impl PType {
|
|||||||
pub fn lower(
|
pub fn lower(
|
||||||
&self,
|
&self,
|
||||||
namespace: &mut NamespaceGuard,
|
namespace: &mut NamespaceGuard,
|
||||||
output: &mut ParserOutput,
|
output: &mut CompilerOutput,
|
||||||
span: FileSpan,
|
span: FileSpan,
|
||||||
) -> Type {
|
) -> Type {
|
||||||
match namespace.get(&self.name).and_then(|ids| ids.ty) {
|
match namespace.get(&self.name).and_then(|ids| ids.ty) {
|
||||||
@@ -60,7 +60,7 @@ impl PType {
|
|||||||
Type::Slice(Box::new(inner))
|
Type::Slice(Box::new(inner))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
output.err(ParserMsg::from_span(span, "Type not found".to_string()));
|
output.err(CompilerMsg::from_span(span, "Type not found".to_string()));
|
||||||
Type::Error
|
Type::Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,48 @@
|
|||||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
||||||
use crate::ir::{IRUInstruction, Size, Type, VarID};
|
use crate::ir::{DataDef, IRUInstruction, Origin, Type, VarInst};
|
||||||
|
|
||||||
impl FnLowerable for PExpr {
|
impl FnLowerable for PExpr {
|
||||||
type Output = VarID;
|
type Output = VarInst;
|
||||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarID> {
|
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<VarInst> {
|
||||||
Some(match self {
|
Some(match self {
|
||||||
PExpr::Lit(l) => match l.as_ref()? {
|
PExpr::Lit(l) => match l.as_ref()? {
|
||||||
super::PLiteral::String(s) => {
|
super::PLiteral::String(s) => {
|
||||||
let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice());
|
let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice());
|
||||||
let data = s.as_bytes().to_vec();
|
let data = s.as_bytes().to_vec();
|
||||||
let len = data.len() as Size;
|
let src = ctx.map.def_data(
|
||||||
let src = ctx.map.def_data(data);
|
DataDef {
|
||||||
ctx.push(IRUInstruction::LoadSlice { dest, src, len });
|
ty: Type::Bits(8).arr(data.len() as u32),
|
||||||
|
origin: Origin::File(l.span),
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
ctx.push(IRUInstruction::LoadSlice { dest, src });
|
||||||
dest
|
dest
|
||||||
}
|
}
|
||||||
super::PLiteral::Char(c) => {
|
super::PLiteral::Char(c) => {
|
||||||
let dest = ctx.map.temp_var(l.span, Type::Bits(8).slice());
|
let ty = Type::Bits(8);
|
||||||
let src = ctx.map.def_data(c.to_string().as_bytes().to_vec());
|
let dest = ctx.map.temp_var(l.span, ty.clone());
|
||||||
|
let src = ctx.map.def_data(
|
||||||
|
DataDef {
|
||||||
|
ty,
|
||||||
|
origin: Origin::File(l.span),
|
||||||
|
},
|
||||||
|
c.to_string().as_bytes().to_vec(),
|
||||||
|
);
|
||||||
ctx.push(IRUInstruction::LoadData { dest, src });
|
ctx.push(IRUInstruction::LoadData { dest, src });
|
||||||
dest
|
dest
|
||||||
}
|
}
|
||||||
super::PLiteral::Number(n) => {
|
super::PLiteral::Number(n) => {
|
||||||
// TODO: temp
|
// TODO: temp
|
||||||
|
let ty = Type::Bits(64);
|
||||||
let dest = ctx.map.temp_var(l.span, Type::Bits(64));
|
let dest = ctx.map.temp_var(l.span, Type::Bits(64));
|
||||||
let src = ctx
|
let src = ctx.map.def_data(
|
||||||
.map
|
DataDef {
|
||||||
.def_data(n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec());
|
ty,
|
||||||
|
origin: Origin::File(l.span),
|
||||||
|
},
|
||||||
|
n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
|
||||||
|
);
|
||||||
ctx.push(IRUInstruction::LoadData { dest, src });
|
ctx.push(IRUInstruction::LoadData { dest, src });
|
||||||
dest
|
dest
|
||||||
}
|
}
|
||||||
@@ -44,7 +61,7 @@ impl FnLowerable for PExpr {
|
|||||||
let res = e.lower(ctx)?;
|
let res = e.lower(ctx)?;
|
||||||
match op {
|
match op {
|
||||||
UnaryOp::Ref => {
|
UnaryOp::Ref => {
|
||||||
let temp = ctx.temp(ctx.map.get_var(res).ty.clone());
|
let temp = ctx.temp(ctx.map.get_var(res.id).ty.clone());
|
||||||
ctx.push(IRUInstruction::Ref {
|
ctx.push(IRUInstruction::Ref {
|
||||||
dest: temp,
|
dest: temp,
|
||||||
src: res,
|
src: res,
|
||||||
@@ -52,7 +69,7 @@ impl FnLowerable for PExpr {
|
|||||||
temp
|
temp
|
||||||
}
|
}
|
||||||
UnaryOp::Deref => {
|
UnaryOp::Deref => {
|
||||||
let t = &ctx.map.get_var(res).ty;
|
let t = &ctx.map.get_var(res.id).ty;
|
||||||
let Type::Ref(inner) = t else {
|
let Type::Ref(inner) = t else {
|
||||||
ctx.err(format!(
|
ctx.err(format!(
|
||||||
"Cannot dereference type {:?}",
|
"Cannot dereference type {:?}",
|
||||||
@@ -77,7 +94,7 @@ impl FnLowerable for PExpr {
|
|||||||
let arg = arg.lower(ctx)?;
|
let arg = arg.lower(ctx)?;
|
||||||
nargs.push(arg);
|
nargs.push(arg);
|
||||||
}
|
}
|
||||||
let def = ctx.map.get_fn_var(fe);
|
let def = ctx.map.get_fn_var(fe.id);
|
||||||
let ty = match def {
|
let ty = match def {
|
||||||
Some(def) => def.ret.clone(),
|
Some(def) => def.ret.clone(),
|
||||||
None => {
|
None => {
|
||||||
@@ -85,7 +102,7 @@ impl FnLowerable for PExpr {
|
|||||||
e.span,
|
e.span,
|
||||||
format!(
|
format!(
|
||||||
"Expected function, found {}",
|
"Expected function, found {}",
|
||||||
ctx.map.type_name(&ctx.map.get_var(fe).ty)
|
ctx.map.type_name(&ctx.map.get_var(fe.id).ty)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
Type::Error
|
Type::Error
|
||||||
@@ -100,6 +117,7 @@ impl FnLowerable for PExpr {
|
|||||||
temp
|
temp
|
||||||
}
|
}
|
||||||
PExpr::Group(e) => e.lower(ctx)?,
|
PExpr::Group(e) => e.lower(ctx)?,
|
||||||
|
PExpr::Construct(c) => todo!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use super::{FnLowerable, Node, PFunction, ParserMsg, ParserOutput};
|
use super::{CompilerMsg, CompilerOutput, FileSpan, FnLowerable, Node, PFunction};
|
||||||
use crate::{
|
use crate::{
|
||||||
ir::{
|
ir::{
|
||||||
FileSpan, FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard,
|
FnDef, FnID, IRInstructions, IRUFunction, IRUInstruction, Idents, NamespaceGuard, Origin,
|
||||||
Origin, Type, VarDef, VarID,
|
Type, VarDef, VarID, VarInst,
|
||||||
},
|
},
|
||||||
parser,
|
parser,
|
||||||
};
|
};
|
||||||
@@ -11,7 +11,7 @@ impl Node<PFunction> {
|
|||||||
pub fn lower_header(
|
pub fn lower_header(
|
||||||
&self,
|
&self,
|
||||||
map: &mut NamespaceGuard,
|
map: &mut NamespaceGuard,
|
||||||
output: &mut ParserOutput,
|
output: &mut CompilerOutput,
|
||||||
) -> Option<FnID> {
|
) -> Option<FnID> {
|
||||||
self.as_ref()?.lower_header(map, output)
|
self.as_ref()?.lower_header(map, output)
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ impl Node<PFunction> {
|
|||||||
&self,
|
&self,
|
||||||
id: FnID,
|
id: FnID,
|
||||||
map: &mut NamespaceGuard,
|
map: &mut NamespaceGuard,
|
||||||
output: &mut ParserOutput,
|
output: &mut CompilerOutput,
|
||||||
) -> Option<IRUFunction> {
|
) -> Option<IRUFunction> {
|
||||||
Some(self.as_ref()?.lower_body(id, map, output))
|
Some(self.as_ref()?.lower_body(id, map, output))
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ impl PFunction {
|
|||||||
pub fn lower_header(
|
pub fn lower_header(
|
||||||
&self,
|
&self,
|
||||||
map: &mut NamespaceGuard,
|
map: &mut NamespaceGuard,
|
||||||
output: &mut ParserOutput,
|
output: &mut CompilerOutput,
|
||||||
) -> Option<FnID> {
|
) -> Option<FnID> {
|
||||||
let header = self.header.as_ref()?;
|
let header = self.header.as_ref()?;
|
||||||
let name = header.name.as_ref()?;
|
let name = header.name.as_ref()?;
|
||||||
@@ -59,7 +59,7 @@ impl PFunction {
|
|||||||
&self,
|
&self,
|
||||||
id: FnID,
|
id: FnID,
|
||||||
map: &mut NamespaceGuard,
|
map: &mut NamespaceGuard,
|
||||||
output: &mut ParserOutput,
|
output: &mut CompilerOutput,
|
||||||
) -> IRUFunction {
|
) -> IRUFunction {
|
||||||
let mut instructions = IRInstructions::new();
|
let mut instructions = IRInstructions::new();
|
||||||
let def = map.get_fn(id).clone();
|
let def = map.get_fn(id).clone();
|
||||||
@@ -71,7 +71,7 @@ impl PFunction {
|
|||||||
span: self.body.span,
|
span: self.body.span,
|
||||||
};
|
};
|
||||||
if let Some(src) = self.body.lower(&mut ctx) {
|
if let Some(src) = self.body.lower(&mut ctx) {
|
||||||
instructions.push(IRUInstruction::Ret { src });
|
instructions.push(IRUInstruction::Ret { src }, src.span);
|
||||||
}
|
}
|
||||||
IRUFunction::new(def.name.clone(), args, instructions)
|
IRUFunction::new(def.name.clone(), args, instructions)
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ impl PFunction {
|
|||||||
pub struct FnLowerCtx<'a, 'n> {
|
pub struct FnLowerCtx<'a, 'n> {
|
||||||
pub map: &'a mut NamespaceGuard<'n>,
|
pub map: &'a mut NamespaceGuard<'n>,
|
||||||
pub instructions: &'a mut IRInstructions,
|
pub instructions: &'a mut IRInstructions,
|
||||||
pub output: &'a mut ParserOutput,
|
pub output: &'a mut CompilerOutput,
|
||||||
pub span: FileSpan,
|
pub span: FileSpan,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ impl<'n> FnLowerCtx<'_, 'n> {
|
|||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarID> {
|
pub fn get_var(&mut self, node: &Node<parser::PIdent>) -> Option<VarInst> {
|
||||||
let ids = self.get(node)?;
|
let ids = self.get(node)?;
|
||||||
if ids.var.is_none() {
|
if ids.var.is_none() {
|
||||||
self.err_at(
|
self.err_at(
|
||||||
@@ -112,19 +112,25 @@ impl<'n> FnLowerCtx<'_, 'n> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ids.var
|
ids.var.map(|id| VarInst {
|
||||||
|
id,
|
||||||
|
span: node.span,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn err(&mut self, msg: String) {
|
pub fn err(&mut self, msg: String) {
|
||||||
self.output.err(ParserMsg::from_span(self.span, msg))
|
self.output.err(CompilerMsg::from_span(self.span, msg))
|
||||||
}
|
}
|
||||||
pub fn err_at(&mut self, span: FileSpan, msg: String) {
|
pub fn err_at(&mut self, span: FileSpan, msg: String) {
|
||||||
self.output.err(ParserMsg::from_span(span, msg))
|
self.output.err(CompilerMsg::from_span(span, msg))
|
||||||
}
|
}
|
||||||
pub fn temp(&mut self, ty: Type) -> VarID {
|
pub fn temp(&mut self, ty: Type) -> VarInst {
|
||||||
self.map.temp_var(self.span, ty)
|
self.map.temp_var(self.span, ty)
|
||||||
}
|
}
|
||||||
pub fn push(&mut self, i: IRUInstruction) {
|
pub fn push(&mut self, i: IRUInstruction) {
|
||||||
self.instructions.push(i);
|
self.instructions.push(i, self.span);
|
||||||
|
}
|
||||||
|
pub fn push_at(&mut self, i: IRUInstruction, span: FileSpan) {
|
||||||
|
self.instructions.push(i, span);
|
||||||
}
|
}
|
||||||
pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> {
|
pub fn sub<'b>(&'b mut self) -> FnLowerCtx<'b, 'n> {
|
||||||
FnLowerCtx {
|
FnLowerCtx {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::ir::NamespaceGuard;
|
use crate::ir::NamespaceGuard;
|
||||||
|
|
||||||
use super::{PModule, ParserOutput};
|
use super::{PModule, CompilerOutput};
|
||||||
|
|
||||||
impl PModule {
|
impl PModule {
|
||||||
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut ParserOutput) {
|
pub fn lower(&self, map: &mut NamespaceGuard, output: &mut CompilerOutput) {
|
||||||
let mut fns = Vec::new();
|
let mut fns = Vec::new();
|
||||||
for f in &self.functions {
|
for f in &self.functions {
|
||||||
if let Some(id) = f.lower_header(map, output) {
|
if let Some(id) = f.lower_header(map, output) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
mod ctx;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod error;
|
mod error;
|
||||||
mod lower;
|
mod lower;
|
||||||
@@ -5,13 +6,11 @@ mod node;
|
|||||||
mod nodes;
|
mod nodes;
|
||||||
mod parse;
|
mod parse;
|
||||||
mod token;
|
mod token;
|
||||||
mod ctx;
|
|
||||||
|
|
||||||
|
use crate::common::{CompilerMsg, CompilerOutput, FileSpan, FilePos};
|
||||||
|
pub use ctx::*;
|
||||||
pub use cursor::*;
|
pub use cursor::*;
|
||||||
pub use error::*;
|
|
||||||
pub use lower::*;
|
|
||||||
pub use node::*;
|
pub use node::*;
|
||||||
pub use nodes::*;
|
pub use nodes::*;
|
||||||
pub use parse::*;
|
pub use parse::*;
|
||||||
pub use token::*;
|
pub use token::*;
|
||||||
pub use ctx::*;
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::{
|
|||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ir::FileSpan;
|
use super::FileSpan;
|
||||||
|
|
||||||
pub struct Node<T> {
|
pub struct Node<T> {
|
||||||
pub inner: Option<T>,
|
pub inner: Option<T>,
|
||||||
@@ -46,4 +46,3 @@ impl<T: Debug> Debug for Node<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::{PIdent, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol};
|
use super::{Node, PIdent, Parsable, ParseResult, ParserCtx, Symbol, CompilerMsg};
|
||||||
|
|
||||||
pub struct PInstruction {
|
pub struct PInstruction {
|
||||||
pub op: Node<PIdent>,
|
pub op: Node<PIdent>,
|
||||||
@@ -38,7 +38,7 @@ impl Parsable for PAsmArg {
|
|||||||
|
|
||||||
let next = ctx.expect_peek()?;
|
let next = ctx.expect_peek()?;
|
||||||
if !next.is_symbol(Symbol::OpenCurly) {
|
if !next.is_symbol(Symbol::OpenCurly) {
|
||||||
return ParseResult::Err(ParserMsg::unexpected_token(
|
return ParseResult::Err(CompilerMsg::unexpected_token(
|
||||||
next,
|
next,
|
||||||
"An identifier or {identifier}",
|
"An identifier or {identifier}",
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
token::Symbol, Node, NodeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, PStatement,
|
token::Symbol, Node, NodeParsable, PStatement, Parsable, ParseResult, ParserCtx, CompilerMsg,
|
||||||
};
|
};
|
||||||
use crate::util::Padder;
|
use crate::util::Padder;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ impl Parsable for PBlock {
|
|||||||
loop {
|
loop {
|
||||||
let Some(next) = ctx.peek() else {
|
let Some(next) = ctx.peek() else {
|
||||||
recover = true;
|
recover = true;
|
||||||
ctx.err(ParserMsg::unexpected_end());
|
ctx.err(CompilerMsg::unexpected_end());
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if next.is_symbol(Symbol::CloseCurly) {
|
if next.is_symbol(Symbol::CloseCurly) {
|
||||||
@@ -36,7 +36,7 @@ impl Parsable for PBlock {
|
|||||||
expect_semi = false;
|
expect_semi = false;
|
||||||
continue;
|
continue;
|
||||||
} else if expect_semi {
|
} else if expect_semi {
|
||||||
ctx.err(ParserMsg {
|
ctx.err(CompilerMsg {
|
||||||
msg: "expected ';'".to_string(),
|
msg: "expected ';'".to_string(),
|
||||||
spans: vec![ctx.next_start().char_span()],
|
spans: vec![ctx.next_start().char_span()],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
PIdent, MaybeParsable, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token, PType,
|
MaybeParsable, Node, PExpr, PIdent, PType, Parsable, ParseResult, ParserCtx, Symbol,
|
||||||
|
Token, CompilerMsg
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct PVarDef {
|
pub struct PVarDef {
|
||||||
@@ -9,6 +10,11 @@ pub struct PVarDef {
|
|||||||
pub ty: Option<Node<PType>>,
|
pub ty: Option<Node<PType>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PFieldDef {
|
||||||
|
pub name: Node<PIdent>,
|
||||||
|
pub val: Option<Node<PExpr>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Parsable for PVarDef {
|
impl Parsable for PVarDef {
|
||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
let name = ctx.parse()?;
|
let name = ctx.parse()?;
|
||||||
@@ -21,6 +27,21 @@ impl Parsable for PVarDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Parsable for PFieldDef {
|
||||||
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
|
let name = ctx.parse()?;
|
||||||
|
if ctx.peek().is_some_and(|n| n.is_symbol(Symbol::Colon)) {
|
||||||
|
ctx.next();
|
||||||
|
ctx.parse().map(|ty| Self {
|
||||||
|
name,
|
||||||
|
val: Some(ty),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ParseResult::Ok(Self { name, val: None })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SelfVar {
|
pub struct SelfVar {
|
||||||
pub ty: SelfType,
|
pub ty: SelfType,
|
||||||
}
|
}
|
||||||
@@ -32,7 +53,7 @@ pub enum SelfType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MaybeParsable for SelfVar {
|
impl MaybeParsable for SelfVar {
|
||||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, super::ParserMsg> {
|
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
|
||||||
if let Some(mut next) = ctx.peek() {
|
if let Some(mut next) = ctx.peek() {
|
||||||
let mut ty = SelfType::Take;
|
let mut ty = SelfType::Take;
|
||||||
if next.is_symbol(Symbol::Ampersand) {
|
if next.is_symbol(Symbol::Ampersand) {
|
||||||
@@ -47,7 +68,7 @@ impl MaybeParsable for SelfVar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ty != SelfType::Take {
|
if ty != SelfType::Take {
|
||||||
return Err(ParserMsg::unexpected_token(next, "self"));
|
return Err(CompilerMsg::unexpected_token(next, "self"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -64,6 +85,16 @@ impl Debug for PVarDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for PFieldDef {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.name.fmt(f)?;
|
||||||
|
if let Some(val) = &self.val {
|
||||||
|
write!(f, ": {:?}", val)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Debug for SelfVar {
|
impl Debug for SelfVar {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
use std::fmt::{Debug, Write};
|
use std::fmt::{Debug, Write};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
op::{PInfixOp, UnaryOp},
|
op::{PInfixOp, UnaryOp}, util::parse_list, Keyword, Node, NodeParsable, PAsmBlock, PBlock, PConstruct, PIdent, PLiteral, Parsable, ParseResult, ParserCtx, Symbol, CompilerMsg
|
||||||
util::parse_list,
|
|
||||||
PAsmBlock, PBlock, PIdent, Keyword, PLiteral, Node, NodeParsable, Parsable, ParseResult, ParserCtx,
|
|
||||||
ParserMsg, Symbol,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type BoxNode = Node<Box<PExpr>>;
|
type BoxNode = Node<Box<PExpr>>;
|
||||||
@@ -18,6 +15,7 @@ pub enum PExpr {
|
|||||||
Call(BoxNode, Vec<Node<PExpr>>),
|
Call(BoxNode, Vec<Node<PExpr>>),
|
||||||
Group(BoxNode),
|
Group(BoxNode),
|
||||||
AsmBlock(Node<PAsmBlock>),
|
AsmBlock(Node<PAsmBlock>),
|
||||||
|
Construct(Node<PConstruct>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for PExpr {
|
impl Parsable for PExpr {
|
||||||
@@ -63,7 +61,7 @@ impl Parsable for PExpr {
|
|||||||
Self::Ident(res.node)
|
Self::Ident(res.node)
|
||||||
} else {
|
} else {
|
||||||
let next = ctx.expect_peek()?;
|
let next = ctx.expect_peek()?;
|
||||||
return ParseResult::Err(ParserMsg::unexpected_token(next, "an expression"));
|
return ParseResult::Err(CompilerMsg::unexpected_token(next, "an expression"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let Some(mut next) = ctx.peek() else {
|
let Some(mut next) = ctx.peek() else {
|
||||||
@@ -140,6 +138,7 @@ impl Debug for PExpr {
|
|||||||
}
|
}
|
||||||
PExpr::Group(inner) => inner.fmt(f)?,
|
PExpr::Group(inner) => inner.fmt(f)?,
|
||||||
PExpr::AsmBlock(inner) => inner.fmt(f)?,
|
PExpr::AsmBlock(inner) => inner.fmt(f)?,
|
||||||
|
PExpr::Construct(inner) => inner.fmt(f)?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, ParserMsg, Token};
|
use super::{MaybeParsable, Parsable, ParseResult, ParserCtx, Token, CompilerMsg};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
@@ -11,7 +11,7 @@ impl Parsable for PIdent {
|
|||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
let next = ctx.expect_peek()?;
|
let next = ctx.expect_peek()?;
|
||||||
let Token::Word(name) = &next.token else {
|
let Token::Word(name) = &next.token else {
|
||||||
return ParseResult::Err(ParserMsg::unexpected_token(next, "an identifier"));
|
return ParseResult::Err(CompilerMsg::unexpected_token(next, "an identifier"));
|
||||||
};
|
};
|
||||||
let name = name.to_string();
|
let name = name.to_string();
|
||||||
ctx.next();
|
ctx.next();
|
||||||
@@ -20,7 +20,7 @@ impl Parsable for PIdent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MaybeParsable for PIdent {
|
impl MaybeParsable for PIdent {
|
||||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> {
|
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
|
||||||
let Some(next) = ctx.peek() else { return Ok(None) };
|
let Some(next) = ctx.peek() else { return Ok(None) };
|
||||||
let Token::Word(name) = &next.token else {
|
let Token::Word(name) = &next.token else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::{CharCursor, MaybeParsable, ParserCtx, ParserMsg, Symbol, Token};
|
use super::{CharCursor, MaybeParsable, ParserCtx, CompilerMsg, Symbol, Token};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
@@ -17,7 +17,7 @@ pub struct PNumber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MaybeParsable for PLiteral {
|
impl MaybeParsable for PLiteral {
|
||||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg> {
|
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg> {
|
||||||
let inst = ctx.expect_peek()?;
|
let inst = ctx.expect_peek()?;
|
||||||
Ok(Some(match &inst.token {
|
Ok(Some(match &inst.token {
|
||||||
Token::Symbol(Symbol::SingleQuote) => {
|
Token::Symbol(Symbol::SingleQuote) => {
|
||||||
@@ -37,7 +37,7 @@ impl MaybeParsable for PLiteral {
|
|||||||
if !first.is_ascii_digit() {
|
if !first.is_ascii_digit() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
let (whole, ty) = parse_whole_num(text);
|
let (whole, ty) = parse_whole_num(&text);
|
||||||
let mut num = PNumber {
|
let mut num = PNumber {
|
||||||
whole,
|
whole,
|
||||||
decimal: None,
|
decimal: None,
|
||||||
@@ -81,7 +81,7 @@ pub fn parse_whole_num(text: &str) -> (String, Option<String>) {
|
|||||||
(whole, if ty.is_empty() { None } else { Some(ty) })
|
(whole, if ty.is_empty() { None } else { Some(ty) })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string_from(cursor: &mut CharCursor) -> Result<String, ParserMsg> {
|
pub fn string_from(cursor: &mut CharCursor) -> Result<String, CompilerMsg> {
|
||||||
let mut str = String::new();
|
let mut str = String::new();
|
||||||
loop {
|
loop {
|
||||||
let c = cursor.expect_next()?;
|
let c = cursor.expect_next()?;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use super::{
|
use super::{
|
||||||
PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg,
|
PFunction, PImpl, Keyword, Node, Parsable, ParseResult, ParserCtx, CompilerMsg,
|
||||||
PStruct, Symbol, Token, PTrait,
|
PStruct, Symbol, Token, PTrait,
|
||||||
};
|
};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@@ -52,18 +52,18 @@ impl Parsable for PModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
ctx.err(ParserMsg::unexpected_token(next, "a definition"));
|
ctx.err(CompilerMsg::unexpected_token(next, "a definition"));
|
||||||
ctx.next();
|
ctx.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if next.is_symbol(Symbol::Semicolon) {
|
} else if next.is_symbol(Symbol::Semicolon) {
|
||||||
ctx.hint(ParserMsg::from_instances(
|
ctx.hint(CompilerMsg::from_instances(
|
||||||
&[next],
|
&[next],
|
||||||
"unneeded semicolon".to_string(),
|
"unneeded semicolon".to_string(),
|
||||||
));
|
));
|
||||||
ctx.next();
|
ctx.next();
|
||||||
} else {
|
} else {
|
||||||
ctx.err(ParserMsg::unexpected_token(next, "a definition"));
|
ctx.err(CompilerMsg::unexpected_token(next, "a definition"));
|
||||||
ctx.next();
|
ctx.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
util::parse_list, PIdent, Keyword, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol,
|
util::parse_list, Keyword, Node, PExpr, PFieldDef, PIdent, PType, PVarDef, Parsable,
|
||||||
PType, PVarDef,
|
ParseResult, ParserCtx, CompilerMsg, Symbol,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -11,6 +11,12 @@ pub struct PStruct {
|
|||||||
pub fields: PStructFields,
|
pub fields: PStructFields,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PConstruct {
|
||||||
|
pub name: Node<PIdent>,
|
||||||
|
pub fields: PConstructFields,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PStructFields {
|
pub enum PStructFields {
|
||||||
Named(Vec<Node<PVarDef>>),
|
Named(Vec<Node<PVarDef>>),
|
||||||
@@ -18,6 +24,13 @@ pub enum PStructFields {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PConstructFields {
|
||||||
|
Named(Vec<Node<PFieldDef>>),
|
||||||
|
Tuple(Vec<Node<PExpr>>),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
impl Parsable for PStruct {
|
impl Parsable for PStruct {
|
||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
ctx.expect_kw(Keyword::Struct)?;
|
ctx.expect_kw(Keyword::Struct)?;
|
||||||
@@ -33,7 +46,7 @@ impl Parsable for PStruct {
|
|||||||
ctx.next();
|
ctx.next();
|
||||||
PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
|
PStructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
|
||||||
} else {
|
} else {
|
||||||
let msg = ParserMsg::unexpected_token(next, "`;`, `(`, or `{`");
|
let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`");
|
||||||
ctx.err(msg);
|
ctx.err(msg);
|
||||||
return ParseResult::Recover(PStruct {
|
return ParseResult::Recover(PStruct {
|
||||||
name,
|
name,
|
||||||
@@ -43,3 +56,29 @@ impl Parsable for PStruct {
|
|||||||
ParseResult::Ok(PStruct { name, fields })
|
ParseResult::Ok(PStruct { name, fields })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Parsable for PConstruct {
|
||||||
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
|
ctx.expect_kw(Keyword::Struct)?;
|
||||||
|
let name = ctx.parse()?;
|
||||||
|
let next = ctx.expect_peek()?;
|
||||||
|
let fields = if next.is_symbol(Symbol::Semicolon) {
|
||||||
|
ctx.next();
|
||||||
|
PConstructFields::None
|
||||||
|
} else if next.is_symbol(Symbol::OpenCurly) {
|
||||||
|
ctx.next();
|
||||||
|
PConstructFields::Named(parse_list(ctx, Symbol::CloseCurly)?)
|
||||||
|
} else if next.is_symbol(Symbol::OpenParen) {
|
||||||
|
ctx.next();
|
||||||
|
PConstructFields::Tuple(parse_list(ctx, Symbol::CloseParen)?)
|
||||||
|
} else {
|
||||||
|
let msg = CompilerMsg::unexpected_token(next, "`;`, `(`, or `{`");
|
||||||
|
ctx.err(msg);
|
||||||
|
return ParseResult::Recover(PConstruct {
|
||||||
|
name,
|
||||||
|
fields: PConstructFields::None,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
ParseResult::Ok(PConstruct { name, fields })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, ParserMsg, Symbol, Token};
|
use super::{util::parse_list, Node, Parsable, ParseResult, ParserCtx, CompilerMsg, Symbol, Token};
|
||||||
|
|
||||||
pub struct PType {
|
pub struct PType {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -19,7 +19,7 @@ impl Parsable for PType {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let Token::Word(name) = &next.token else {
|
let Token::Word(name) = &next.token else {
|
||||||
return ParseResult::Err(ParserMsg::unexpected_token(next, "a type identifier"));
|
return ParseResult::Err(CompilerMsg::unexpected_token(next, "a type identifier"));
|
||||||
};
|
};
|
||||||
let n = name.to_string();
|
let n = name.to_string();
|
||||||
ctx.next();
|
ctx.next();
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use super::{Node, Parsable, ParserCtx, ParserMsg, Symbol};
|
use super::{Node, Parsable, ParserCtx, CompilerMsg, Symbol};
|
||||||
|
|
||||||
pub fn parse_list_sep<T: Parsable>(
|
pub fn parse_list_sep<T: Parsable>(
|
||||||
ctx: &mut ParserCtx,
|
ctx: &mut ParserCtx,
|
||||||
sep: Symbol,
|
sep: Symbol,
|
||||||
end: Symbol,
|
end: Symbol,
|
||||||
) -> Result<Vec<Node<T>>, ParserMsg> {
|
) -> Result<Vec<Node<T>>, CompilerMsg> {
|
||||||
let mut vals = Vec::new();
|
let mut vals = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let next = ctx.expect_peek()?;
|
let next = ctx.expect_peek()?;
|
||||||
@@ -29,14 +29,14 @@ pub fn parse_list_sep<T: Parsable>(
|
|||||||
pub fn parse_list<T: Parsable>(
|
pub fn parse_list<T: Parsable>(
|
||||||
ctx: &mut ParserCtx,
|
ctx: &mut ParserCtx,
|
||||||
end: Symbol,
|
end: Symbol,
|
||||||
) -> Result<Vec<Node<T>>, ParserMsg> {
|
) -> Result<Vec<Node<T>>, CompilerMsg> {
|
||||||
parse_list_sep(ctx, Symbol::Comma, end)
|
parse_list_sep(ctx, Symbol::Comma, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_list_nosep<T: Parsable>(
|
pub fn parse_list_nosep<T: Parsable>(
|
||||||
ctx: &mut ParserCtx,
|
ctx: &mut ParserCtx,
|
||||||
end: Symbol,
|
end: Symbol,
|
||||||
) -> Result<Vec<Node<T>>, ParserMsg> {
|
) -> Result<Vec<Node<T>>, CompilerMsg> {
|
||||||
let mut vals = Vec::new();
|
let mut vals = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
let next = ctx.expect_peek()?;
|
let next = ctx.expect_peek()?;
|
||||||
|
|||||||
@@ -3,14 +3,12 @@ use std::{
|
|||||||
ops::{ControlFlow, FromResidual, Try},
|
ops::{ControlFlow, FromResidual, Try},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ir::FilePos;
|
use super::{CompilerMsg, FilePos, Node, ParserCtx};
|
||||||
|
|
||||||
use super::{Node, ParserCtx, ParserMsg};
|
|
||||||
|
|
||||||
pub enum ParseResult<T> {
|
pub enum ParseResult<T> {
|
||||||
Ok(T),
|
Ok(T),
|
||||||
Recover(T),
|
Recover(T),
|
||||||
Err(ParserMsg),
|
Err(CompilerMsg),
|
||||||
SubErr,
|
SubErr,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +24,7 @@ impl<T> ParseResult<T> {
|
|||||||
|
|
||||||
impl<T> Try for ParseResult<T> {
|
impl<T> Try for ParseResult<T> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
type Residual = Option<ParserMsg>;
|
type Residual = Option<CompilerMsg>;
|
||||||
fn from_output(output: Self::Output) -> Self {
|
fn from_output(output: Self::Output) -> Self {
|
||||||
Self::Ok(output)
|
Self::Ok(output)
|
||||||
}
|
}
|
||||||
@@ -50,8 +48,8 @@ impl<T> FromResidual for ParseResult<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> FromResidual<Result<Infallible, ParserMsg>> for ParseResult<T> {
|
impl<T> FromResidual<Result<Infallible, CompilerMsg>> for ParseResult<T> {
|
||||||
fn from_residual(residual: Result<Infallible, ParserMsg>) -> Self {
|
fn from_residual(residual: Result<Infallible, CompilerMsg>) -> Self {
|
||||||
match residual {
|
match residual {
|
||||||
Err(e) => Self::Err(e),
|
Err(e) => Self::Err(e),
|
||||||
}
|
}
|
||||||
@@ -115,14 +113,28 @@ pub trait Parsable: Sized {
|
|||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self>;
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MaybeParsable: Sized {
|
pub trait ParsableWith: Sized {
|
||||||
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, ParserMsg>;
|
type Data;
|
||||||
|
|
||||||
|
fn parse(ctx: &mut ParserCtx, data: Self::Data) -> ParseResult<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Parsable> Node<T> {
|
pub trait MaybeParsable: Sized {
|
||||||
pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult<T> {
|
fn maybe_parse(ctx: &mut ParserCtx) -> Result<Option<Self>, CompilerMsg>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Parsable> ParsableWith for T {
|
||||||
|
type Data = ();
|
||||||
|
|
||||||
|
fn parse(ctx: &mut ParserCtx, _: Self::Data) -> ParseResult<Self> {
|
||||||
|
T::parse(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ParsableWith> Node<T> {
|
||||||
|
pub fn parse_with(ctx: &mut ParserCtx, data: T::Data) -> NodeParseResult<T> {
|
||||||
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
|
let start = ctx.peek().map(|t| t.span.start).unwrap_or(FilePos::start());
|
||||||
let (inner, recover) = match T::parse(ctx) {
|
let (inner, recover) = match T::parse(ctx, data) {
|
||||||
ParseResult::Ok(v) => (Some(v), false),
|
ParseResult::Ok(v) => (Some(v), false),
|
||||||
ParseResult::Recover(v) => (Some(v), true),
|
ParseResult::Recover(v) => (Some(v), true),
|
||||||
ParseResult::Err(e) => {
|
ParseResult::Err(e) => {
|
||||||
@@ -142,6 +154,12 @@ impl<T: Parsable> Node<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Parsable> Node<T> {
|
||||||
|
pub fn parse(ctx: &mut ParserCtx) -> NodeParseResult<T> {
|
||||||
|
Node::parse_with(ctx, ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: MaybeParsable> Node<T> {
|
impl<T: MaybeParsable> Node<T> {
|
||||||
pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> {
|
pub fn maybe_parse(ctx: &mut ParserCtx) -> Option<Self> {
|
||||||
let start = ctx.next_start();
|
let start = ctx.next_start();
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::{iter::Peekable, str::Chars};
|
use std::{iter::Peekable, str::Chars};
|
||||||
|
|
||||||
use super::super::ParserMsg;
|
use super::super::{CompilerMsg, FilePos};
|
||||||
use crate::ir::FilePos;
|
|
||||||
|
|
||||||
pub struct CharCursor<'a> {
|
pub struct CharCursor<'a> {
|
||||||
chars: Peekable<Chars<'a>>,
|
chars: Peekable<Chars<'a>>,
|
||||||
@@ -15,12 +14,12 @@ impl CharCursor<'_> {
|
|||||||
self.advance();
|
self.advance();
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
pub fn expect(&mut self, c: char) -> Result<(), ParserMsg> {
|
pub fn expect(&mut self, c: char) -> Result<(), CompilerMsg> {
|
||||||
let next = self.expect_next()?;
|
let next = self.expect_next()?;
|
||||||
if next == c {
|
if next == c {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ParserMsg::at(
|
Err(CompilerMsg::at(
|
||||||
self.prev_pos,
|
self.prev_pos,
|
||||||
format!("unexpected char '{next}'; expected '{c}'"),
|
format!("unexpected char '{next}'; expected '{c}'"),
|
||||||
))
|
))
|
||||||
@@ -46,8 +45,8 @@ impl CharCursor<'_> {
|
|||||||
self.next_pos.col += 1;
|
self.next_pos.col += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn expect_next(&mut self) -> Result<char, ParserMsg> {
|
pub fn expect_next(&mut self) -> Result<char, CompilerMsg> {
|
||||||
self.next().ok_or(ParserMsg::unexpected_end())
|
self.next().ok_or(CompilerMsg::unexpected_end())
|
||||||
}
|
}
|
||||||
pub fn next_pos(&self) -> FilePos {
|
pub fn next_pos(&self) -> FilePos {
|
||||||
self.next_pos
|
self.next_pos
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ use std::ops::Deref;
|
|||||||
pub use cursor::*;
|
pub use cursor::*;
|
||||||
pub use keyword::*;
|
pub use keyword::*;
|
||||||
pub use symbol::*;
|
pub use symbol::*;
|
||||||
|
use super::FileSpan;
|
||||||
use crate::ir::FileSpan;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
|
|||||||
Reference in New Issue
Block a user