Big things coming

This commit is contained in:
vanten-s 2025-09-08 16:04:31 +02:00
parent 4020536ae6
commit d9bea76666
6 changed files with 801 additions and 150 deletions

183
src/code_gen.rs Normal file
View 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
View 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;
}

View file

@ -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"),
}
} }
} }

View file

@ -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(())
} }

View file

@ -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
View 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)
}
}