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;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum TokenType {
|
||||
OpenParantheses,
|
||||
ClosedParantheses,
|
||||
Integer(usize),
|
||||
Dot,
|
||||
Integer(isize),
|
||||
String(String),
|
||||
Identifier(String),
|
||||
Keyword(Keyword),
|
||||
Macro(Macro),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Token {
|
||||
row: usize,
|
||||
col: usize,
|
||||
pub row: usize,
|
||||
pub col: usize,
|
||||
|
||||
token_type: TokenType,
|
||||
pub token_type: TokenType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
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)]
|
||||
|
@ -38,9 +54,9 @@ struct UnfinishedTokenString {
|
|||
#[derive(Error, Debug)]
|
||||
#[error("Syntax error at: {row}:{col}. {message}")]
|
||||
pub struct LexerError {
|
||||
row: usize,
|
||||
col: usize,
|
||||
message: String,
|
||||
pub row: usize,
|
||||
pub col: usize,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl FromStr for TokenString {
|
||||
|
@ -51,7 +67,7 @@ impl FromStr for TokenString {
|
|||
tokens: Vec::new(),
|
||||
eof: false,
|
||||
|
||||
row: 0,
|
||||
row: 1,
|
||||
col: 1,
|
||||
};
|
||||
|
||||
|
@ -84,10 +100,12 @@ impl Lexer for UnfinishedTokenString {
|
|||
use TokenType as TT;
|
||||
|
||||
let token_type = match self.input[self.position] as char {
|
||||
'(' => Ok(TT::OpenParantheses),
|
||||
')' => Ok(TT::ClosedParantheses),
|
||||
'a'..='z' | 'A'..='Z' => Ok(TT::Identifier(self.lex_identifier())),
|
||||
'(' => { self.next_char(); Ok(TT::OpenParantheses) },
|
||||
')' => { self.next_char(); Ok(TT::ClosedParantheses) },
|
||||
'.' => { self.next_char(); Ok(TT::Dot) },
|
||||
'a'..='z' | 'A'..='Z' | ':' => Ok(self.lex_identifier()),
|
||||
'0'..='9' | '-' => Ok(TT::Integer(self.lex_integer())),
|
||||
'"' => Ok(TT::String(self.lex_string())),
|
||||
v => Err(format!("Expected new token, found: {v}")),
|
||||
};
|
||||
|
||||
|
@ -107,8 +125,6 @@ impl Lexer for UnfinishedTokenString {
|
|||
};
|
||||
|
||||
self.tokens.push(token);
|
||||
|
||||
self.next_char();
|
||||
self.skip_whitespace();
|
||||
}
|
||||
|
||||
|
@ -140,11 +156,61 @@ impl UnfinishedTokenString {
|
|||
}
|
||||
}
|
||||
|
||||
fn lex_identifier(&mut self) -> String {
|
||||
todo!()
|
||||
fn lex_identifier(&mut self) -> TokenType {
|
||||
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();
|
||||
}
|
||||
|
||||
fn lex_integer(&mut self) -> usize {
|
||||
todo!()
|
||||
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) -> isize {
|
||||
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 code_gen;
|
||||
mod ir;
|
||||
mod lexer;
|
||||
// mod parser;
|
||||
mod parser;
|
||||
|
||||
mod error;
|
||||
|
||||
use color_eyre::eyre::Result;
|
||||
// pub use error::*;
|
||||
use ir::IRepr;
|
||||
use lexer::TokenString;
|
||||
use parser::SExpression;
|
||||
|
||||
use crate::{
|
||||
code_gen::{EightBitLang, GenerateCode, Scope},
|
||||
ir::generate_code,
|
||||
};
|
||||
|
||||
fn main() -> Result<()> {
|
||||
// let code = "(+ 1 (+ 5 5))".to_string();
|
||||
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 {
|
||||
print!("{byte:#X}, ");
|
||||
}
|
||||
|
||||
println!(""); */
|
||||
Ok(())
|
||||
}
|
||||
|
|
223
src/parser.rs
223
src/parser.rs
|
@ -1,143 +1,134 @@
|
|||
use crate::*;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Parser {
|
||||
row: usize,
|
||||
column: usize,
|
||||
lines: Vec<Vec<char>>,
|
||||
use color_eyre::eyre::Error;
|
||||
|
||||
use crate::lexer::{Keyword, Macro, Token, TokenString, TokenType};
|
||||
|
||||
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)]
|
||||
pub(crate) struct Instruction {
|
||||
pub name: String,
|
||||
pub arguments: Vec<Value>,
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct State {
|
||||
expression: Vec<Token>,
|
||||
index: usize,
|
||||
_functions: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum Value {
|
||||
Instruction(Instruction),
|
||||
StringLiteral(String),
|
||||
IntegerLiteral(u32),
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum LispAtom {
|
||||
Integer(isize),
|
||||
String(String),
|
||||
Identifier(String),
|
||||
Keyword(Keyword),
|
||||
Macro(Macro),
|
||||
}
|
||||
|
||||
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<_>>(),
|
||||
impl TryFrom<TokenString> for Vec<SExpression> {
|
||||
fn try_from(value: TokenString) -> Result<Self, Self::Error> {
|
||||
let list = value.tokens;
|
||||
|
||||
let mut expressions = vec![];
|
||||
|
||||
let mut state = State {
|
||||
expression: list,
|
||||
index: 0,
|
||||
_functions: Vec::new(),
|
||||
};
|
||||
parser.instruction()
|
||||
|
||||
while state.index != state.expression.len() {
|
||||
expressions.push(SExpression::parse_sexpression(&mut state)?);
|
||||
state.index += 1;
|
||||
}
|
||||
|
||||
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(());
|
||||
Ok(expressions)
|
||||
}
|
||||
|
||||
fn jump_whitespace(&mut self) -> Option<()> {
|
||||
self.increment()?;
|
||||
while self.lines[self.row][self.column].is_whitespace() {
|
||||
self.increment()?;
|
||||
}
|
||||
Some(())
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl SExpression {
|
||||
fn parse_sexpression(state: &mut State) -> Result<Self, Error> {
|
||||
let expr = match &state.expression[state.index].token_type {
|
||||
TokenType::OpenParantheses => Self::parse_expression(state),
|
||||
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 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(),
|
||||
}));
|
||||
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;
|
||||
|
||||
self.jump_whitespace();
|
||||
let expression_1 = dbg!(Self::parse_sexpression(state)?);
|
||||
state.index += 1;
|
||||
|
||||
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()?));
|
||||
// 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 {
|
||||
arguments.push(Value::Identifier(self.identifier()?));
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
elements.reverse();
|
||||
|
||||
let pair = Self::make_pair_list(elements);
|
||||
return Ok(pair);
|
||||
}
|
||||
}
|
||||
|
||||
self.jump_whitespace();
|
||||
|
||||
return Ok(Instruction { name, arguments });
|
||||
fn make_pair_list(mut expressions: Vec<SExpression>) -> SExpression {
|
||||
if expressions.len() == 1 {
|
||||
return SExpression::Pair(Box::new(expressions[0].clone()), Box::new(NIL.clone()));
|
||||
}
|
||||
|
||||
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> {
|
||||
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)
|
||||
return SExpression::Pair(
|
||||
Box::new(
|
||||
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