Big things coming
This commit is contained in:
parent
4020536ae6
commit
d9bea76666
183
src/code_gen.rs
Normal file
183
src/code_gen.rs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
use std::{collections::HashMap, ops::AddAssign};
|
||||||
|
|
||||||
|
use color_eyre::eyre::Error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
lexer::Keyword,
|
||||||
|
parser::{LispAtom, SExpression},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum InstructionFrom {
|
||||||
|
ROM,
|
||||||
|
RAM,
|
||||||
|
ALU,
|
||||||
|
RegisterC,
|
||||||
|
RegisterD,
|
||||||
|
|
||||||
|
RegisterSP,
|
||||||
|
RegisterSB,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum InstructionTo {
|
||||||
|
JumpAddressUpper,
|
||||||
|
JumpAddressLower,
|
||||||
|
|
||||||
|
Jump,
|
||||||
|
|
||||||
|
RamAddressUpper,
|
||||||
|
RamAddressLower,
|
||||||
|
|
||||||
|
RAM,
|
||||||
|
|
||||||
|
Flags,
|
||||||
|
|
||||||
|
RegisterA,
|
||||||
|
RegisterB,
|
||||||
|
RegisterC,
|
||||||
|
RegisterD,
|
||||||
|
|
||||||
|
RegisterSP,
|
||||||
|
RegisterSB,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
struct Command {
|
||||||
|
data_from: InstructionFrom,
|
||||||
|
data_to: InstructionTo,
|
||||||
|
data: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Scope {
|
||||||
|
variables: Vec<String>,
|
||||||
|
stack_position: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct EightBitLang {
|
||||||
|
instructions: Vec<Command>,
|
||||||
|
labels: Option<HashMap<String, usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GenerateCode {
|
||||||
|
fn to_code(self, codegen_scope: &mut Scope) -> Result<EightBitLang, Self::Error>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
|
type Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenerateCode for SExpression {
|
||||||
|
fn to_code(self, codegen_scope: &mut Scope) -> Result<EightBitLang, Self::Error> {
|
||||||
|
match self {
|
||||||
|
SExpression::Atom(a) => a.to_code(codegen_scope),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenerateCode for LispAtom {
|
||||||
|
fn to_code(self, codegen_scope: &mut Scope) -> Result<EightBitLang, Self::Error> {
|
||||||
|
match self {
|
||||||
|
LispAtom::Keyword(keyword) => keyword.to_code(codegen_scope),
|
||||||
|
LispAtom::Integer(number) => number.to_code(codegen_scope),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenerateCode for isize {
|
||||||
|
fn to_code(self, codegen_scope: &mut Scope) -> Result<EightBitLang, Self::Error> {
|
||||||
|
if let Err(_e) = i8::try_from(self) {
|
||||||
|
return Err(Error::msg("Yo integer too big brah"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(EightBitLang::push(self as i8, codegen_scope));
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenerateCode for Keyword {
|
||||||
|
fn to_code(self, _codegen_scope: &mut Scope) -> Result<EightBitLang, Self::Error> {
|
||||||
|
match self {
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for EightBitLang {
|
||||||
|
fn add_assign(&mut self, mut rhs: Self) {
|
||||||
|
let mut labels = self.labels.clone().unwrap();
|
||||||
|
if rhs.labels.is_some() || self.labels.is_some() {
|
||||||
|
if self.labels.is_none() {
|
||||||
|
labels = rhs.labels.unwrap();
|
||||||
|
} else if rhs.labels.is_none() {
|
||||||
|
} else {
|
||||||
|
labels = HashMap::new();
|
||||||
|
for label in rhs.labels.unwrap() {
|
||||||
|
labels.insert(label.0, label.1 + self.instructions.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.labels = Some(labels);
|
||||||
|
}
|
||||||
|
self.instructions.append(&mut rhs.instructions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Command> for EightBitLang {
|
||||||
|
fn from(value: Command) -> Self {
|
||||||
|
Self {
|
||||||
|
instructions: vec![value],
|
||||||
|
labels: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EightBitLang {
|
||||||
|
fn push(value: i8, codegen_scope: &mut Scope) -> Self {
|
||||||
|
use InstructionFrom as IF;
|
||||||
|
use InstructionTo as IT;
|
||||||
|
|
||||||
|
codegen_scope.stack_position += 1;
|
||||||
|
|
||||||
|
let mut commands = Vec::new();
|
||||||
|
commands.push(Command::new(IF::RegisterSP, IT::RegisterA, 0x00));
|
||||||
|
commands.push(Command::new(IF::ROM, IT::RegisterB, 0x01));
|
||||||
|
commands.push(Command::new(IF::ALU, IT::RegisterSP, 0x00));
|
||||||
|
commands.push(Command::new(IF::RegisterSP, IT::RamAddressLower, 0x00));
|
||||||
|
commands.push(Command::new(IF::ROM, IT::RAM, value));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
instructions: commands,
|
||||||
|
labels: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
fn new(data_from: InstructionFrom, data_to: InstructionTo, data: i8) -> Self {
|
||||||
|
Self {
|
||||||
|
data_from,
|
||||||
|
data_to,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
variables: Vec::new(),
|
||||||
|
stack_position: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
253
src/ir.rs
Normal file
253
src/ir.rs
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
ops::{Add, AddAssign},
|
||||||
|
};
|
||||||
|
|
||||||
|
use color_eyre::eyre::Error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
lexer::{Keyword, Macro},
|
||||||
|
parser::{LispAtom, SExpression, NIL},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct IRepr {
|
||||||
|
commands: Vec<Command>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
enum Command {
|
||||||
|
PushInt(isize),
|
||||||
|
PushSum,
|
||||||
|
PopR1,
|
||||||
|
PopR2,
|
||||||
|
PopOut,
|
||||||
|
PushRelative(usize),
|
||||||
|
|
||||||
|
Enter,
|
||||||
|
Leave,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Scope {
|
||||||
|
stack_position: usize,
|
||||||
|
stack_positions: Vec<usize>,
|
||||||
|
variables: HashMap<String, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_code(expressions: Vec<SExpression>) -> Result<IRepr, Error> {
|
||||||
|
let mut scope = Scope {
|
||||||
|
stack_position: 0,
|
||||||
|
stack_positions: vec![],
|
||||||
|
variables: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut sum = IRepr::new();
|
||||||
|
|
||||||
|
for expression in expressions {
|
||||||
|
sum += expression.to_irepr(&mut scope)?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ToIR {
|
||||||
|
fn to_irepr(self, ir_scope: &mut Scope) -> Result<IRepr, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ToIRMacro {
|
||||||
|
fn to_irepr(self, ir_scope: &mut Scope, expressions: SExpression) -> Result<IRepr, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIR for SExpression {
|
||||||
|
fn to_irepr(self, ir_scope: &mut Scope) -> Result<IRepr, Error> {
|
||||||
|
Ok(match self {
|
||||||
|
Self::Atom(a) => a.to_irepr(ir_scope)?,
|
||||||
|
Self::Pair(a, b) => match *a {
|
||||||
|
Self::Atom(LispAtom::Macro(m)) => m.to_irepr(ir_scope, *b)?,
|
||||||
|
a => b.to_irepr(ir_scope)? + a.to_irepr(ir_scope)?,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIR for LispAtom {
|
||||||
|
fn to_irepr(self, ir_scope: &mut Scope) -> Result<IRepr, Error> {
|
||||||
|
match self {
|
||||||
|
Self::Integer(number) => number.to_irepr(ir_scope),
|
||||||
|
Self::Keyword(keyword) => keyword.to_irepr(ir_scope),
|
||||||
|
Self::Identifier(identifier) => {
|
||||||
|
if !ir_scope.variables.contains_key(&identifier) {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
ir_scope.stack_position += 1;
|
||||||
|
Ok(IRepr {
|
||||||
|
commands: vec![
|
||||||
|
Command::PushRelative(ir_scope.variables[&identifier]),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIR for Keyword {
|
||||||
|
fn to_irepr(self, ir_scope: &mut Scope) -> Result<IRepr, Error> {
|
||||||
|
match self {
|
||||||
|
Self::Nil => Ok(IRepr { commands: vec![] }),
|
||||||
|
Self::Add => {
|
||||||
|
ir_scope.stack_position -= 1;
|
||||||
|
Ok(IRepr {
|
||||||
|
commands: vec![Command::PopR1, Command::PopR2, Command::PushSum],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Self::Out => {
|
||||||
|
ir_scope.stack_position -= 1;
|
||||||
|
Ok(IRepr {
|
||||||
|
commands: vec![Command::PopOut],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIR for isize {
|
||||||
|
fn to_irepr(self, ir_scope: &mut Scope) -> Result<IRepr, Error> {
|
||||||
|
ir_scope.stack_position += 1;
|
||||||
|
return Ok(Command::PushInt(self).to_irepr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIRMacro for Macro {
|
||||||
|
fn to_irepr(self, ir_scope: &mut Scope, expression: SExpression) -> Result<IRepr, Error> {
|
||||||
|
match self {
|
||||||
|
Self::Let => {
|
||||||
|
println!("Parsing a let expression");
|
||||||
|
let (mut varlist, mut body) = match expression {
|
||||||
|
SExpression::Atom(_a) => todo!(),
|
||||||
|
SExpression::Pair(a, b) => (*a, *b),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut commands = IRepr {
|
||||||
|
commands: vec![Command::Enter],
|
||||||
|
};
|
||||||
|
|
||||||
|
ir_scope.stack_positions.push(ir_scope.stack_position);
|
||||||
|
ir_scope.stack_position = 0;
|
||||||
|
|
||||||
|
while varlist != NIL {
|
||||||
|
let var = match varlist {
|
||||||
|
SExpression::Atom(_) => panic!("Let defined wrong"),
|
||||||
|
SExpression::Pair(a, b) => {
|
||||||
|
varlist = *b;
|
||||||
|
*a
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match var {
|
||||||
|
SExpression::Atom(a) => {
|
||||||
|
let name = match a {
|
||||||
|
LispAtom::Identifier(ident) => ident,
|
||||||
|
_ => todo!(),
|
||||||
|
};
|
||||||
|
ir_scope.variables.insert(name, ir_scope.stack_position);
|
||||||
|
ir_scope.stack_position += 1;
|
||||||
|
commands += Command::PushInt(0);
|
||||||
|
}
|
||||||
|
SExpression::Pair(name, car) => {
|
||||||
|
let name = match *name {
|
||||||
|
SExpression::Atom(a) => match a {
|
||||||
|
LispAtom::Identifier(ident) => ident,
|
||||||
|
_ => todo!(),
|
||||||
|
},
|
||||||
|
_ => todo!(),
|
||||||
|
};
|
||||||
|
commands += car.to_irepr(ir_scope)?;
|
||||||
|
ir_scope.variables.insert(name, ir_scope.stack_position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg!(&commands);
|
||||||
|
dbg!(&ir_scope);
|
||||||
|
|
||||||
|
while body != NIL {
|
||||||
|
match body {
|
||||||
|
SExpression::Atom(_a) => todo!(),
|
||||||
|
SExpression::Pair(a, b) => {
|
||||||
|
commands += a.to_irepr(ir_scope)?;
|
||||||
|
body = *b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg!(&commands);
|
||||||
|
dbg!(&ir_scope);
|
||||||
|
|
||||||
|
commands += Command::Leave;
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
fn to_irepr(self) -> IRepr {
|
||||||
|
IRepr {
|
||||||
|
commands: vec![self],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IRepr {
|
||||||
|
fn new() -> IRepr {
|
||||||
|
return IRepr { commands: vec![] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for IRepr {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.commands.extend(rhs.commands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<Vec<Command>> for IRepr {
|
||||||
|
fn add_assign(&mut self, rhs: Vec<Command>) {
|
||||||
|
self.commands.extend(rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Vec<Command>> for IRepr {
|
||||||
|
fn add(mut self, rhs: Vec<Command>) -> Self::Output {
|
||||||
|
self += rhs;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Output = Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<Command> for IRepr {
|
||||||
|
fn add_assign(&mut self, rhs: Command) {
|
||||||
|
self.commands.push(rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Command> for IRepr {
|
||||||
|
fn add(mut self, rhs: Command) -> Self::Output {
|
||||||
|
self += rhs;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Output = Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for IRepr {
|
||||||
|
fn add(mut self, rhs: Self) -> Self::Output {
|
||||||
|
self += rhs;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Output = Self;
|
||||||
|
}
|
108
src/lexer.rs
108
src/lexer.rs
|
@ -1,27 +1,43 @@
|
||||||
use std::str::FromStr;
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
OpenParantheses,
|
OpenParantheses,
|
||||||
ClosedParantheses,
|
ClosedParantheses,
|
||||||
Integer(usize),
|
Dot,
|
||||||
|
Integer(isize),
|
||||||
String(String),
|
String(String),
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
|
Keyword(Keyword),
|
||||||
|
Macro(Macro),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
row: usize,
|
pub row: usize,
|
||||||
col: usize,
|
pub col: usize,
|
||||||
|
|
||||||
token_type: TokenType,
|
pub token_type: TokenType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TokenString {
|
pub struct TokenString {
|
||||||
tokens: Vec<Token>,
|
pub tokens: Vec<Token>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum Keyword {
|
||||||
|
Add,
|
||||||
|
Out,
|
||||||
|
Nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum Macro {
|
||||||
|
Let,
|
||||||
|
Defun,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -38,9 +54,9 @@ struct UnfinishedTokenString {
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
#[error("Syntax error at: {row}:{col}. {message}")]
|
#[error("Syntax error at: {row}:{col}. {message}")]
|
||||||
pub struct LexerError {
|
pub struct LexerError {
|
||||||
row: usize,
|
pub row: usize,
|
||||||
col: usize,
|
pub col: usize,
|
||||||
message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for TokenString {
|
impl FromStr for TokenString {
|
||||||
|
@ -51,7 +67,7 @@ impl FromStr for TokenString {
|
||||||
tokens: Vec::new(),
|
tokens: Vec::new(),
|
||||||
eof: false,
|
eof: false,
|
||||||
|
|
||||||
row: 0,
|
row: 1,
|
||||||
col: 1,
|
col: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,10 +100,12 @@ impl Lexer for UnfinishedTokenString {
|
||||||
use TokenType as TT;
|
use TokenType as TT;
|
||||||
|
|
||||||
let token_type = match self.input[self.position] as char {
|
let token_type = match self.input[self.position] as char {
|
||||||
'(' => Ok(TT::OpenParantheses),
|
'(' => { self.next_char(); Ok(TT::OpenParantheses) },
|
||||||
')' => Ok(TT::ClosedParantheses),
|
')' => { self.next_char(); Ok(TT::ClosedParantheses) },
|
||||||
'a'..='z' | 'A'..='Z' => Ok(TT::Identifier(self.lex_identifier())),
|
'.' => { self.next_char(); Ok(TT::Dot) },
|
||||||
|
'a'..='z' | 'A'..='Z' | ':' => Ok(self.lex_identifier()),
|
||||||
'0'..='9' | '-' => Ok(TT::Integer(self.lex_integer())),
|
'0'..='9' | '-' => Ok(TT::Integer(self.lex_integer())),
|
||||||
|
'"' => Ok(TT::String(self.lex_string())),
|
||||||
v => Err(format!("Expected new token, found: {v}")),
|
v => Err(format!("Expected new token, found: {v}")),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,8 +125,6 @@ impl Lexer for UnfinishedTokenString {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.tokens.push(token);
|
self.tokens.push(token);
|
||||||
|
|
||||||
self.next_char();
|
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,11 +156,61 @@ impl UnfinishedTokenString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lex_identifier(&mut self) -> String {
|
fn lex_identifier(&mut self) -> TokenType {
|
||||||
todo!()
|
let mut ident: String = String::new();
|
||||||
|
while !self.eof && self.input[self.position].is_ascii_alphanumeric() {
|
||||||
|
ident += &String::from_utf8_lossy(&[self.input[self.position]]);
|
||||||
|
self.next_char();
|
||||||
|
}
|
||||||
|
|
||||||
|
use Keyword as K;
|
||||||
|
use Macro as M;
|
||||||
|
use TokenType as TT;
|
||||||
|
match ident.as_str() {
|
||||||
|
"add" => TT::Keyword(K::Add),
|
||||||
|
"out" => TT::Keyword(K::Out),
|
||||||
|
"nil" => TT::Keyword(K::Nil),
|
||||||
|
"let" => TT::Macro(M::Let),
|
||||||
|
"defun" => TT::Macro(M::Defun),
|
||||||
|
_ => TT::Identifier(ident),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lex_integer(&mut self) -> usize {
|
fn lex_integer(&mut self) -> isize {
|
||||||
todo!()
|
let mut number: String = String::new();
|
||||||
|
while !self.eof && self.input[self.position].is_ascii_digit() {
|
||||||
|
number += &String::from_utf8_lossy(&[self.input[self.position]]);
|
||||||
|
self.next_char();
|
||||||
|
}
|
||||||
|
number.parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lex_string(&mut self) -> String {
|
||||||
|
let mut string: String = String::new();
|
||||||
|
self.next_char();
|
||||||
|
while !self.eof && !(self.input[self.position] == '"' as u8) {
|
||||||
|
string += &String::from_utf8_lossy(&[self.input[self.position]]);
|
||||||
|
self.next_char();
|
||||||
|
}
|
||||||
|
string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Keyword {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Add => write!(f, "add"),
|
||||||
|
Self::Nil => write!(f, "nil"),
|
||||||
|
Self::Out => write!(f, "out"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Macro {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Let => write!(f, "let"),
|
||||||
|
Self::Defun => write!(f, "defun"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
29
src/main.rs
29
src/main.rs
|
@ -1,32 +1,47 @@
|
||||||
// mod assembler;
|
// mod assembler;
|
||||||
|
mod code_gen;
|
||||||
|
mod ir;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
// mod parser;
|
mod parser;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
// pub use error::*;
|
// pub use error::*;
|
||||||
|
use ir::IRepr;
|
||||||
use lexer::TokenString;
|
use lexer::TokenString;
|
||||||
|
use parser::SExpression;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
code_gen::{EightBitLang, GenerateCode, Scope},
|
||||||
|
ir::generate_code,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// let code = "(+ 1 (+ 5 5))".to_string();
|
// let code = "(+ 1 (+ 5 5))".to_string();
|
||||||
color_eyre::install()?;
|
color_eyre::install()?;
|
||||||
|
|
||||||
let code = "()".to_string();
|
// let code = r#"(mul 2 (add 3 4))"#.to_string();
|
||||||
|
|
||||||
let lexed: TokenString = code.parse()?;
|
// let code = "(add 3 4) (add 1 2)";
|
||||||
|
let code = "(let ((a 3)) (out (add 1 a)) (out (add 2 a)))";
|
||||||
|
|
||||||
dbg!(lexed);
|
let lexed: TokenString = dbg!((code.parse())?);
|
||||||
|
|
||||||
Ok(())
|
let parsed: Vec<SExpression> = (lexed.try_into())?;
|
||||||
|
println!("{parsed:?}");
|
||||||
|
|
||||||
|
let code: IRepr = generate_code(parsed)?;
|
||||||
|
|
||||||
|
// let code: EightBitLang = code.to_code(&mut Scope::new())?;
|
||||||
|
|
||||||
|
dbg!(code);
|
||||||
/*
|
/*
|
||||||
let parsed = dbg!(parser::Parser::parse(code).unwrap());
|
|
||||||
let assembled = assembler::Assembler::assemble(parsed).unwrap();
|
|
||||||
|
|
||||||
for byte in assembled {
|
for byte in assembled {
|
||||||
print!("{byte:#X}, ");
|
print!("{byte:#X}, ");
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(""); */
|
println!(""); */
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
235
src/parser.rs
235
src/parser.rs
|
@ -1,143 +1,134 @@
|
||||||
use crate::*;
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[derive(Debug)]
|
use color_eyre::eyre::Error;
|
||||||
pub struct Parser {
|
|
||||||
row: usize,
|
use crate::lexer::{Keyword, Macro, Token, TokenString, TokenType};
|
||||||
column: usize,
|
|
||||||
lines: Vec<Vec<char>>,
|
pub static NIL: SExpression = SExpression::Atom(LispAtom::Keyword(Keyword::Nil));
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum SExpression {
|
||||||
|
Pair(Box<SExpression>, Box<SExpression>),
|
||||||
|
Atom(LispAtom),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub(crate) struct Instruction {
|
struct State {
|
||||||
pub name: String,
|
expression: Vec<Token>,
|
||||||
pub arguments: Vec<Value>,
|
index: usize,
|
||||||
|
_functions: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub(crate) enum Value {
|
pub enum LispAtom {
|
||||||
Instruction(Instruction),
|
Integer(isize),
|
||||||
StringLiteral(String),
|
String(String),
|
||||||
IntegerLiteral(u32),
|
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
|
Keyword(Keyword),
|
||||||
|
Macro(Macro),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl TryFrom<TokenString> for Vec<SExpression> {
|
||||||
pub fn parse(stream: String) -> Result<Instruction> {
|
fn try_from(value: TokenString) -> Result<Self, Self::Error> {
|
||||||
let mut parser = Parser {
|
let list = value.tokens;
|
||||||
row: 0,
|
|
||||||
column: 0,
|
let mut expressions = vec![];
|
||||||
lines: stream
|
|
||||||
.split('\n')
|
let mut state = State {
|
||||||
.map(|a| a.chars().collect::<Vec<_>>())
|
expression: list,
|
||||||
.collect::<Vec<_>>(),
|
index: 0,
|
||||||
|
_functions: Vec::new(),
|
||||||
};
|
};
|
||||||
parser.instruction()
|
|
||||||
|
while state.index != state.expression.len() {
|
||||||
|
expressions.push(SExpression::parse_sexpression(&mut state)?);
|
||||||
|
state.index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expressions)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment(&mut self) -> Option<()> {
|
type Error = Error;
|
||||||
self.column += 1;
|
}
|
||||||
if self.column == self.lines[self.row].len() {
|
|
||||||
self.row += 1;
|
impl SExpression {
|
||||||
if self.row == self.lines.len() {
|
fn parse_sexpression(state: &mut State) -> Result<Self, Error> {
|
||||||
self.row -= 1;
|
let expr = match &state.expression[state.index].token_type {
|
||||||
self.column -= 1;
|
TokenType::OpenParantheses => Self::parse_expression(state),
|
||||||
return None;
|
TokenType::Integer(val) => Ok(Self::Atom(LispAtom::Integer(val.to_owned()))),
|
||||||
|
TokenType::String(val) => Ok(Self::Atom(LispAtom::String(val.to_owned()))),
|
||||||
|
TokenType::Identifier(val) => Ok(Self::Atom(LispAtom::Identifier(val.to_owned()))),
|
||||||
|
TokenType::Keyword(val) => Ok(Self::Atom(LispAtom::Keyword(val.to_owned()))),
|
||||||
|
TokenType::Macro(val) => Ok(Self::Atom(LispAtom::Macro(val.to_owned()))),
|
||||||
|
_other => Err(Error::msg(format!(
|
||||||
|
"Did not expect symbol at row {} col {}",
|
||||||
|
state.expression[state.index].row, state.expression[state.index].col
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg!(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_expression(state: &mut State) -> Result<Self, Error> {
|
||||||
|
if state.expression[state.index].token_type != TokenType::OpenParantheses {
|
||||||
|
return Err(Error::msg(format!(
|
||||||
|
"Error: Expected ( at row {} col {}",
|
||||||
|
state.expression[state.index].row, state.expression[state.index].col
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
state.index += 1;
|
||||||
|
|
||||||
|
let expression_1 = dbg!(Self::parse_sexpression(state)?);
|
||||||
|
state.index += 1;
|
||||||
|
|
||||||
|
// Is pair
|
||||||
|
if state.expression[state.index].token_type == TokenType::Dot {
|
||||||
|
state.index += 1;
|
||||||
|
let expression_2 = Self::parse_sexpression(state)?;
|
||||||
|
return Ok(Self::Pair(Box::new(expression_1), Box::new(expression_2)));
|
||||||
|
} else {
|
||||||
|
// Is list
|
||||||
|
let mut elements = vec![expression_1];
|
||||||
|
|
||||||
|
while state.expression[state.index].token_type != TokenType::ClosedParantheses {
|
||||||
|
elements.push(Self::parse_sexpression(state)?);
|
||||||
|
state.index += 1;
|
||||||
}
|
}
|
||||||
self.column = 0;
|
|
||||||
}
|
|
||||||
return Some(());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn jump_whitespace(&mut self) -> Option<()> {
|
elements.reverse();
|
||||||
self.increment()?;
|
|
||||||
while self.lines[self.row][self.column].is_whitespace() {
|
|
||||||
self.increment()?;
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn instruction(&mut self) -> Result<Instruction> {
|
let pair = Self::make_pair_list(elements);
|
||||||
if self.lines[self.row][self.column] != '(' {
|
return Ok(pair);
|
||||||
return Err(Error::SyntaxError(SyntaxError {
|
|
||||||
row: self.row,
|
|
||||||
column: self.column,
|
|
||||||
message: "SyntaxError: Expected '('".to_string(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.jump_whitespace();
|
|
||||||
|
|
||||||
let name = self.identifier()?;
|
|
||||||
|
|
||||||
let mut arguments = Vec::new();
|
|
||||||
|
|
||||||
while self.lines[self.row][self.column] != ')' {
|
|
||||||
match self.lines[self.row][self.column] {
|
|
||||||
'\"' => arguments.push(Value::StringLiteral(self.string_literal()?)),
|
|
||||||
'(' => arguments.push(Value::Instruction(self.instruction()?)),
|
|
||||||
character => {
|
|
||||||
if character.is_numeric() {
|
|
||||||
arguments.push(Value::IntegerLiteral(self.integer_literal()?));
|
|
||||||
} else {
|
|
||||||
arguments.push(Value::Identifier(self.identifier()?));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.jump_whitespace();
|
|
||||||
|
|
||||||
return Ok(Instruction { name, arguments });
|
|
||||||
}
|
|
||||||
|
|
||||||
fn string_literal(&mut self) -> Result<String> {
|
|
||||||
self.increment();
|
|
||||||
|
|
||||||
let mut accumulator = String::new();
|
|
||||||
|
|
||||||
while self.lines[self.row][self.column] != '"' {
|
|
||||||
accumulator.push(self.lines[self.row][self.column]);
|
|
||||||
self.increment();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.jump_whitespace();
|
|
||||||
|
|
||||||
Ok(accumulator)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn integer_literal(&mut self) -> Result<u32> {
|
|
||||||
let mut accumulator = String::new();
|
|
||||||
|
|
||||||
while self.lines[self.row][self.column].is_numeric() {
|
|
||||||
accumulator.push(self.lines[self.row][self.column]);
|
|
||||||
self.increment();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.jump_whitespace();
|
|
||||||
|
|
||||||
match accumulator.parse() {
|
|
||||||
Ok(v) => Ok(v),
|
|
||||||
Err(_e) => Err(Error::SyntaxError(SyntaxError {
|
|
||||||
row: self.row,
|
|
||||||
column: self.column,
|
|
||||||
message: "Couldn't parse integer literal".to_string(),
|
|
||||||
})),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn identifier(&mut self) -> Result<String> {
|
fn make_pair_list(mut expressions: Vec<SExpression>) -> SExpression {
|
||||||
let mut accumulator = String::new();
|
if expressions.len() == 1 {
|
||||||
|
return SExpression::Pair(Box::new(expressions[0].clone()), Box::new(NIL.clone()));
|
||||||
let mut current = self.lines[self.row][self.column];
|
|
||||||
|
|
||||||
while !"()\"".contains(current) && !current.is_whitespace() {
|
|
||||||
accumulator.push(self.lines[self.row][self.column]);
|
|
||||||
self.increment();
|
|
||||||
current = self.lines[self.row][self.column];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.jump_whitespace();
|
return SExpression::Pair(
|
||||||
|
Box::new(
|
||||||
Ok(accumulator)
|
expressions
|
||||||
|
.pop()
|
||||||
|
.expect("The length should be more than one"),
|
||||||
|
),
|
||||||
|
Box::new(Self::make_pair_list(expressions)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for SExpression {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Pair(a, b) => write!(f, "({a} . {b})"),
|
||||||
|
Self::Atom(a) => match a {
|
||||||
|
LispAtom::String(a) => write!(f, "\"{a}\""),
|
||||||
|
LispAtom::Integer(a) => write!(f, "{a}"),
|
||||||
|
LispAtom::Keyword(a) => write!(f, "{a}"),
|
||||||
|
LispAtom::Identifier(a) => write!(f, "{a}"),
|
||||||
|
LispAtom::Macro(a) => write!(f, "{a}"),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
143
src/parser_old.rs
Normal file
143
src/parser_old.rs
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
use crate::{error::{Error, SyntaxError}, *};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Parser {
|
||||||
|
row: usize,
|
||||||
|
column: usize,
|
||||||
|
lines: Vec<Vec<char>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct Instruction {
|
||||||
|
pub name: String,
|
||||||
|
pub arguments: Vec<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum Value {
|
||||||
|
Instruction(Instruction),
|
||||||
|
StringLiteral(String),
|
||||||
|
IntegerLiteral(u32),
|
||||||
|
Identifier(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub fn parse(stream: String) -> Result<Instruction> {
|
||||||
|
let mut parser = Parser {
|
||||||
|
row: 0,
|
||||||
|
column: 0,
|
||||||
|
lines: stream
|
||||||
|
.split('\n')
|
||||||
|
.map(|a| a.chars().collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
};
|
||||||
|
parser.instruction()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increment(&mut self) -> Option<()> {
|
||||||
|
self.column += 1;
|
||||||
|
if self.column == self.lines[self.row].len() {
|
||||||
|
self.row += 1;
|
||||||
|
if self.row == self.lines.len() {
|
||||||
|
self.row -= 1;
|
||||||
|
self.column -= 1;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.column = 0;
|
||||||
|
}
|
||||||
|
return Some(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jump_whitespace(&mut self) -> Option<()> {
|
||||||
|
self.increment()?;
|
||||||
|
while self.lines[self.row][self.column].is_whitespace() {
|
||||||
|
self.increment()?;
|
||||||
|
}
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instruction(&mut self) -> Result<Instruction> {
|
||||||
|
if self.lines[self.row][self.column] != '(' {
|
||||||
|
return Err(Error::SyntaxError(SyntaxError {
|
||||||
|
row: self.row,
|
||||||
|
column: self.column,
|
||||||
|
message: "SyntaxError: Expected '('".to_string(),
|
||||||
|
}).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.jump_whitespace();
|
||||||
|
|
||||||
|
let name = self.identifier()?;
|
||||||
|
|
||||||
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
|
while self.lines[self.row][self.column] != ')' {
|
||||||
|
match self.lines[self.row][self.column] {
|
||||||
|
'\"' => arguments.push(Value::StringLiteral(self.string_literal()?)),
|
||||||
|
'(' => arguments.push(Value::Instruction(self.instruction()?)),
|
||||||
|
character => {
|
||||||
|
if character.is_numeric() {
|
||||||
|
arguments.push(Value::IntegerLiteral(self.integer_literal()?));
|
||||||
|
} else {
|
||||||
|
arguments.push(Value::Identifier(self.identifier()?));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.jump_whitespace();
|
||||||
|
|
||||||
|
return Ok(Instruction { name, arguments });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string_literal(&mut self) -> Result<String> {
|
||||||
|
self.increment();
|
||||||
|
|
||||||
|
let mut accumulator = String::new();
|
||||||
|
|
||||||
|
while self.lines[self.row][self.column] != '"' {
|
||||||
|
accumulator.push(self.lines[self.row][self.column]);
|
||||||
|
self.increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.jump_whitespace();
|
||||||
|
|
||||||
|
Ok(accumulator)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn integer_literal(&mut self) -> Result<u32> {
|
||||||
|
let mut accumulator = String::new();
|
||||||
|
|
||||||
|
while self.lines[self.row][self.column].is_numeric() {
|
||||||
|
accumulator.push(self.lines[self.row][self.column]);
|
||||||
|
self.increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.jump_whitespace();
|
||||||
|
|
||||||
|
match accumulator.parse() {
|
||||||
|
Ok(v) => Ok(v),
|
||||||
|
Err(_e) => Err(Error::SyntaxError(SyntaxError {
|
||||||
|
row: self.row,
|
||||||
|
column: self.column,
|
||||||
|
message: "Couldn't parse integer literal".to_string(),
|
||||||
|
}).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn identifier(&mut self) -> Result<String> {
|
||||||
|
let mut accumulator = String::new();
|
||||||
|
|
||||||
|
let mut current = self.lines[self.row][self.column];
|
||||||
|
|
||||||
|
while !"()\"".contains(current) && !current.is_whitespace() {
|
||||||
|
accumulator.push(self.lines[self.row][self.column]);
|
||||||
|
self.increment();
|
||||||
|
current = self.lines[self.row][self.column];
|
||||||
|
}
|
||||||
|
|
||||||
|
self.jump_whitespace();
|
||||||
|
|
||||||
|
Ok(accumulator)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue