Get basic compiler working
This commit is contained in:
parent
3414aaee9b
commit
b0a4f9dc7e
183
src/compiler.rs
Normal file
183
src/compiler.rs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::errors::CompilerError;
|
||||||
|
use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Position, Statement};
|
||||||
|
|
||||||
|
type Variable = (VariableID, VariableType);
|
||||||
|
type VariableID = u32;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Command {
|
||||||
|
InitializeVariable(VariableID, VariableType),
|
||||||
|
BeginScope,
|
||||||
|
EndScope,
|
||||||
|
Pop(u32), // Pop into registery u32
|
||||||
|
Push(u32), // Push out of registery 32
|
||||||
|
AssignVariable(VariableID, u32), // Assign variable from registery u32
|
||||||
|
VarToReg(VariableID, u32), // Bring Variable to registery u32
|
||||||
|
StringLit(String), // Bring String Literal to Heap
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum VariableType {
|
||||||
|
TypeString,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Compiler {
|
||||||
|
parsed: ParsedReid,
|
||||||
|
root_scope: Scope,
|
||||||
|
list: Vec<Command>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CompiledReid {
|
||||||
|
pub list: Vec<Command>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Compiler {
|
||||||
|
pub fn from(parsed: ParsedReid) -> Compiler {
|
||||||
|
Compiler {
|
||||||
|
parsed,
|
||||||
|
root_scope: Scope::default(),
|
||||||
|
list: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile(mut self) -> Result<CompiledReid, CompilerError> {
|
||||||
|
self.handle_expression(self.parsed.0.clone())?;
|
||||||
|
Ok(CompiledReid { list: self.list })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_expression(
|
||||||
|
&mut self,
|
||||||
|
exp: Expression,
|
||||||
|
) -> Result<Option<VariableType>, CompilerError> {
|
||||||
|
match exp {
|
||||||
|
Expression::BlockExpr(pos, list) => {
|
||||||
|
self.list.push(Command::BeginScope);
|
||||||
|
self.root_scope.begin_scope();
|
||||||
|
|
||||||
|
for statement in list {
|
||||||
|
self.handle_statement(statement)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.root_scope.end_scope(pos)?;
|
||||||
|
self.list.push(Command::EndScope);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Expression::ValueRef(_, val) => match val {
|
||||||
|
Pattern::IdentPattern(pos, ident) => {
|
||||||
|
if let Some(var) = self.root_scope.get(ident.clone()) {
|
||||||
|
self.list.push(Command::VarToReg(var.0, 0));
|
||||||
|
self.list.push(Command::Push(0));
|
||||||
|
Ok(Some(var.1))
|
||||||
|
} else {
|
||||||
|
Err(CompilerError::VariableNotExists(pos, ident))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Pattern::LiteralPattern(_, literal) => {
|
||||||
|
let vtype = self.handle_literal(literal)?;
|
||||||
|
Ok(Some(vtype))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_statement(
|
||||||
|
&mut self,
|
||||||
|
statement: Statement,
|
||||||
|
) -> Result<Option<VariableType>, CompilerError> {
|
||||||
|
match statement {
|
||||||
|
Statement::LetStatement(pos, ident, val) => {
|
||||||
|
let res = self.handle_expression(*val);
|
||||||
|
match res {
|
||||||
|
Ok(vtype) => {
|
||||||
|
if let Some(vtype) = vtype {
|
||||||
|
self.root_scope.add_var(pos, ident.clone(), vtype)?;
|
||||||
|
let var = self.root_scope.get(ident).unwrap();
|
||||||
|
self.list.push(Command::InitializeVariable(var.0, var.1));
|
||||||
|
self.list.push(Command::Pop(0));
|
||||||
|
self.list.push(Command::AssignVariable(var.0, 0));
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err(CompilerError::LetFailed(
|
||||||
|
pos,
|
||||||
|
Box::new(CompilerError::CanNotAssignVoidType),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => Err(CompilerError::LetFailed(pos, Box::new(err))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::ExprStatement(pos, expr) => self.handle_expression(expr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_literal(&mut self, pattern: LiteralPattern) -> Result<VariableType, CompilerError> {
|
||||||
|
match pattern {
|
||||||
|
LiteralPattern::StringLit(string) => self.list.push(Command::StringLit(string)),
|
||||||
|
}
|
||||||
|
Ok(VariableType::TypeString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Scope {
|
||||||
|
counter: VariableID,
|
||||||
|
variables: HashMap<String, Variable>,
|
||||||
|
innerScope: Option<Box<Scope>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
fn get(&self, variable: String) -> Option<Variable> {
|
||||||
|
if let Some(val) = self.variables.get(&variable) {
|
||||||
|
Some(*val)
|
||||||
|
} else if let Some(inner) = &self.innerScope {
|
||||||
|
if let Some(val) = inner.get(variable) {
|
||||||
|
Some((val.0 + self.counter, val.1))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_var(
|
||||||
|
&mut self,
|
||||||
|
pos: Position,
|
||||||
|
variable: String,
|
||||||
|
vtype: VariableType,
|
||||||
|
) -> Result<(), CompilerError> {
|
||||||
|
if self.variables.contains_key(&variable) {
|
||||||
|
Err(CompilerError::VariableExists(pos, variable))
|
||||||
|
} else if let Some(inner) = &mut self.innerScope {
|
||||||
|
inner.add_var(pos, variable, vtype)
|
||||||
|
} else {
|
||||||
|
self.variables.insert(variable, (self.counter, vtype));
|
||||||
|
self.counter += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_scope(&mut self) {
|
||||||
|
if let Some(inner) = &mut self.innerScope {
|
||||||
|
inner.begin_scope();
|
||||||
|
} else {
|
||||||
|
self.innerScope = Some(Box::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_scope(&mut self, pos: Position) -> Result<(), CompilerError> {
|
||||||
|
if let Some(inner) = &mut self.innerScope {
|
||||||
|
if inner.innerScope.is_some() {
|
||||||
|
inner.end_scope(pos)?;
|
||||||
|
} else {
|
||||||
|
self.innerScope = None;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CompilerError::InvalidScopeExit(pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,17 +15,17 @@ impl From<io::Error> for GenericError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CompilerError {
|
pub enum SyntaxError {
|
||||||
Fatal,
|
Fatal,
|
||||||
ExpectedToken(Position, char),
|
ExpectedToken(Position, char),
|
||||||
ExpectedExpression(Position, Option<Box<CompilerError>>),
|
ExpectedExpression(Position, Option<Box<SyntaxError>>),
|
||||||
ExpectedIdent(Position),
|
ExpectedIdent(Position),
|
||||||
ExpectedStatement(Position, Option<Box<CompilerError>>),
|
ExpectedStatement(Position, Option<Box<SyntaxError>>),
|
||||||
ExpectedPattern(Position),
|
ExpectedPattern(Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilerError {
|
impl SyntaxError {
|
||||||
fn from_opt(from: &Option<Box<CompilerError>>) -> String {
|
fn from_opt(from: &Option<Box<SyntaxError>>) -> String {
|
||||||
if let Some(err) = from {
|
if let Some(err) = from {
|
||||||
format!("\n {}", err)
|
format!("\n {}", err)
|
||||||
} else {
|
} else {
|
||||||
@ -34,24 +34,44 @@ impl CompilerError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for CompilerError {
|
impl Display for SyntaxError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let text = match self {
|
let text = match self {
|
||||||
CompilerError::Fatal => "Fatal error".to_string(),
|
SyntaxError::Fatal => "Fatal error".to_string(),
|
||||||
CompilerError::ExpectedToken(pos, c) => format!("Expected token '{}' at {}", c, pos),
|
SyntaxError::ExpectedToken(pos, c) => format!("Expected token '{}' at {}", c, pos),
|
||||||
CompilerError::ExpectedExpression(pos, err) => format!(
|
SyntaxError::ExpectedExpression(pos, err) => format!(
|
||||||
"Expected expression at {}{}",
|
"Expected expression at {}{}",
|
||||||
pos,
|
pos,
|
||||||
CompilerError::from_opt(err)
|
SyntaxError::from_opt(err)
|
||||||
),
|
),
|
||||||
CompilerError::ExpectedIdent(pos) => format!("Expected ident at {}", pos),
|
SyntaxError::ExpectedIdent(pos) => format!("Expected ident at {}", pos),
|
||||||
CompilerError::ExpectedStatement(pos, err) => format!(
|
SyntaxError::ExpectedStatement(pos, err) => format!(
|
||||||
"Expected statement at {}{}",
|
"Expected statement at {}{}",
|
||||||
pos,
|
pos,
|
||||||
CompilerError::from_opt(err)
|
SyntaxError::from_opt(err)
|
||||||
),
|
),
|
||||||
CompilerError::ExpectedPattern(pos) => format!("Expected pattern at {}", pos),
|
SyntaxError::ExpectedPattern(pos) => format!("Expected pattern at {}", pos),
|
||||||
};
|
};
|
||||||
write!(f, "{}", text)
|
write!(f, "{}", text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CompilerError {
|
||||||
|
Fatal,
|
||||||
|
VariableExists(Position, String),
|
||||||
|
VariableNotExists(Position, String),
|
||||||
|
InvalidScopeExit(Position),
|
||||||
|
LetFailed(Position, Box<CompilerError>),
|
||||||
|
CanNotAssignVoidType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompilerError {
|
||||||
|
fn from_opt(from: &Option<Box<SyntaxError>>) -> String {
|
||||||
|
if let Some(err) = from {
|
||||||
|
format!("\n {}", err)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
22
src/main.rs
22
src/main.rs
@ -1,17 +1,29 @@
|
|||||||
|
mod compiler;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod file_io;
|
mod file_io;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
|
use compiler::Compiler;
|
||||||
use file_io::open_file;
|
use file_io::open_file;
|
||||||
use parser::Parser;
|
use parser::Parser;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let path = Path::new("reid_src/test.reid");
|
let path = Path::new("reid_src/test.reid");
|
||||||
let reid = Parser::from(open_file(&path).ok().unwrap()).parse();
|
let parsed = Parser::from(open_file(&path).ok().unwrap()).parse();
|
||||||
if let Err(error) = reid {
|
match parsed {
|
||||||
eprintln!("Syntax error: {}", error);
|
Err(error) => {
|
||||||
std::process::exit(1);
|
eprintln!("Syntax error: {}", error);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
Ok(parsed) => {
|
||||||
|
dbg!(&parsed);
|
||||||
|
let compiled = Compiler::from(parsed).compile();
|
||||||
|
if let Err(error) = compiled {
|
||||||
|
eprintln!("Compilation error: {:#?}", error);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
dbg!(compiled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dbg!(reid);
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
mod parsed_reid;
|
mod parsed_reid;
|
||||||
|
|
||||||
use super::errors::CompilerError;
|
use super::errors::SyntaxError;
|
||||||
use parsed_reid::{Expression, ParsedReid, Statement};
|
pub use parsed_reid::*;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(mut self) -> Result<ParsedReid, CompilerError> {
|
pub fn parse(mut self) -> Result<ParsedReid, SyntaxError> {
|
||||||
let mut statement_list = Vec::new();
|
let mut statement_list = Vec::new();
|
||||||
|
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
@ -211,7 +211,7 @@ impl Expect<'_> {
|
|||||||
}
|
}
|
||||||
self.text
|
self.text
|
||||||
}
|
}
|
||||||
pub fn get_or(self, error: CompilerError) -> Result<String, CompilerError> {
|
pub fn get_or(self, error: SyntaxError) -> Result<String, SyntaxError> {
|
||||||
match self.get() {
|
match self.get() {
|
||||||
Some(text) => Ok(text),
|
Some(text) => Ok(text),
|
||||||
None => Err(error),
|
None => Err(error),
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
use super::{CompilerError, Parser, Position};
|
use super::{Parser, Position, SyntaxError};
|
||||||
|
|
||||||
type Ident = String;
|
type Ident = String;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ParsedReid(pub Expression);
|
pub struct ParsedReid(pub Expression);
|
||||||
#[derive(Debug)]
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
LetStatement(Position, Ident, Box<Expression>),
|
LetStatement(Position, Ident, Box<Expression>),
|
||||||
ExprStatement(Position, Expression),
|
ExprStatement(Position, Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
pub fn parse(parser: &mut Parser) -> Result<Statement, CompilerError> {
|
pub fn parse(parser: &mut Parser) -> Result<Statement, SyntaxError> {
|
||||||
let pos = parser.pos();
|
let pos = parser.pos();
|
||||||
|
|
||||||
if let Some(_) = parser.expect("let").get() {
|
if let Some(_) = parser.expect("let").get() {
|
||||||
let ident = parser
|
let ident = parser
|
||||||
.expect_ident()
|
.expect_ident()
|
||||||
.get_or(CompilerError::ExpectedIdent(pos))?;
|
.get_or(SyntaxError::ExpectedIdent(pos))?;
|
||||||
parser
|
parser
|
||||||
.expect("=")
|
.expect("=")
|
||||||
.get_or(CompilerError::ExpectedToken(pos, '='))?;
|
.get_or(SyntaxError::ExpectedToken(pos, '='))?;
|
||||||
match Expression::parse(parser) {
|
match Expression::parse(parser) {
|
||||||
Ok(expr) => {
|
Ok(expr) => {
|
||||||
parser
|
parser
|
||||||
.expect(";")
|
.expect(";")
|
||||||
.get_or(CompilerError::ExpectedToken(pos, ';'))?;
|
.get_or(SyntaxError::ExpectedToken(pos, ';'))?;
|
||||||
Ok(Statement::LetStatement(pos, ident, Box::new(expr)))
|
Ok(Statement::LetStatement(pos, ident, Box::new(expr)))
|
||||||
}
|
}
|
||||||
Err(err) => Err(CompilerError::ExpectedExpression(pos, Some(Box::new(err)))),
|
Err(err) => Err(SyntaxError::ExpectedExpression(pos, Some(Box::new(err)))),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match Expression::parse(parser) {
|
match Expression::parse(parser) {
|
||||||
@ -37,23 +37,23 @@ impl Statement {
|
|||||||
let statement = Statement::ExprStatement(pos, expr);
|
let statement = Statement::ExprStatement(pos, expr);
|
||||||
parser
|
parser
|
||||||
.expect(";")
|
.expect(";")
|
||||||
.get_or(CompilerError::ExpectedToken(pos, ';'))?;
|
.get_or(SyntaxError::ExpectedToken(pos, ';'))?;
|
||||||
Ok(statement)
|
Ok(statement)
|
||||||
}
|
}
|
||||||
Err(err) => Err(CompilerError::ExpectedStatement(pos, Some(Box::new(err)))),
|
Err(err) => Err(SyntaxError::ExpectedStatement(pos, Some(Box::new(err)))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
BlockExpr(Position, Vec<Statement>),
|
BlockExpr(Position, Vec<Statement>),
|
||||||
ValueRef(Position, Pattern),
|
ValueRef(Position, Pattern),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
pub fn parse(parser: &mut Parser) -> Result<Expression, CompilerError> {
|
pub fn parse(parser: &mut Parser) -> Result<Expression, SyntaxError> {
|
||||||
let begin_pos = parser.pos();
|
let begin_pos = parser.pos();
|
||||||
|
|
||||||
let expect = parser.expect("{");
|
let expect = parser.expect("{");
|
||||||
@ -71,24 +71,24 @@ impl Expression {
|
|||||||
if let Some(_) = parser.expect("}").get() {
|
if let Some(_) = parser.expect("}").get() {
|
||||||
Ok(Expression::BlockExpr(begin_pos, statement_list))
|
Ok(Expression::BlockExpr(begin_pos, statement_list))
|
||||||
} else {
|
} else {
|
||||||
Err(CompilerError::ExpectedToken(parser.pos(), '}'))
|
Err(SyntaxError::ExpectedToken(parser.pos(), '}'))
|
||||||
}
|
}
|
||||||
} else if let Ok(pattern) = Pattern::parse(parser) {
|
} else if let Ok(pattern) = Pattern::parse(parser) {
|
||||||
Ok(Expression::ValueRef(begin_pos, pattern))
|
Ok(Expression::ValueRef(begin_pos, pattern))
|
||||||
} else {
|
} else {
|
||||||
Err(CompilerError::ExpectedExpression(begin_pos, None))
|
Err(SyntaxError::ExpectedExpression(begin_pos, None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
IdentPattern(Position, Ident),
|
IdentPattern(Position, Ident),
|
||||||
LiteralPattern(Position, LiteralPattern),
|
LiteralPattern(Position, LiteralPattern),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern {
|
impl Pattern {
|
||||||
fn parse(parser: &mut Parser) -> Result<Pattern, CompilerError> {
|
fn parse(parser: &mut Parser) -> Result<Pattern, SyntaxError> {
|
||||||
let pos = parser.pos();
|
let pos = parser.pos();
|
||||||
if let Some(string) = parser.expect_string_lit().get() {
|
if let Some(string) = parser.expect_string_lit().get() {
|
||||||
Ok(Pattern::LiteralPattern(
|
Ok(Pattern::LiteralPattern(
|
||||||
@ -98,12 +98,12 @@ impl Pattern {
|
|||||||
} else if let Some(ident) = parser.expect_ident().get() {
|
} else if let Some(ident) = parser.expect_ident().get() {
|
||||||
Ok(Pattern::IdentPattern(pos, ident))
|
Ok(Pattern::IdentPattern(pos, ident))
|
||||||
} else {
|
} else {
|
||||||
Err(CompilerError::ExpectedPattern(pos))
|
Err(SyntaxError::ExpectedPattern(pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LiteralPattern {
|
pub enum LiteralPattern {
|
||||||
StringLit(String),
|
StringLit(String),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user