|
|
@ -0,0 +1,296 @@ |
|
|
|
use crate::{
|
|
|
|
electro_program::ElectroProgram,
|
|
|
|
error_handler::ErrorHandler,
|
|
|
|
external_module::ExternalModule,
|
|
|
|
internal_module::InternalModule,
|
|
|
|
module_param::{ModuleParam, ModuleParamType},
|
|
|
|
stmt::{Connection, Stmt},
|
|
|
|
token::{Token, TokenType},
|
|
|
|
};
|
|
|
|
|
|
|
|
pub struct Parser {
|
|
|
|
tokens: Vec<Token>,
|
|
|
|
current: usize,
|
|
|
|
error_handler: ErrorHandler,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Parser {
|
|
|
|
pub fn new(tokens: Vec<Token>) -> Self {
|
|
|
|
Self {
|
|
|
|
tokens,
|
|
|
|
current: 0,
|
|
|
|
error_handler: ErrorHandler::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn parse(mut self) -> Option<ElectroProgram> {
|
|
|
|
let mut ep = ElectroProgram::new();
|
|
|
|
|
|
|
|
while !self.is_at_end() {
|
|
|
|
if self.try_parse(&mut ep).is_none() {
|
|
|
|
self.synchronize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
println!("{}", self.error_handler.errors.join("\n"));
|
|
|
|
|
|
|
|
Some(ep)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn try_parse(&mut self, ep: &mut ElectroProgram) -> Option<()> {
|
|
|
|
if self.match_type(TokenType::Extern).is_some() {
|
|
|
|
// external
|
|
|
|
ep.add_external(self.external()?);
|
|
|
|
} else if self.match_type(TokenType::Module).is_some() {
|
|
|
|
// internal module
|
|
|
|
ep.add_internal(self.intern_module()?);
|
|
|
|
} else {
|
|
|
|
self.error_handler
|
|
|
|
.error_token(&self.peek(), &format!("Unexpected token."));
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn external(&mut self) -> Option<ExternalModule> {
|
|
|
|
self.consume(TokenType::Module, "Expected 'module' after 'extern'.")?;
|
|
|
|
|
|
|
|
let name = self
|
|
|
|
.consume(
|
|
|
|
TokenType::Identifier,
|
|
|
|
"Expected module name after 'module'.",
|
|
|
|
)?
|
|
|
|
.lexeme;
|
|
|
|
self.consume(TokenType::LeftParen, "Expected '(' after module name.")?;
|
|
|
|
let filename = self.consume_string("Expected filename for extern module declaration.")?; // TODO load external module kicad file
|
|
|
|
self.consume(
|
|
|
|
TokenType::RightParen,
|
|
|
|
"Expected ')' after extern module filename.",
|
|
|
|
)?;
|
|
|
|
self.consume(
|
|
|
|
TokenType::Semicolon,
|
|
|
|
"Expected ';' after extern module declaration.",
|
|
|
|
)?;
|
|
|
|
|
|
|
|
// Params are TODO because they need to be read from the kicad file.
|
|
|
|
// For now, we'll just hardcode it as input, input, output, since that's what we need for logic gates
|
|
|
|
Some(ExternalModule::new(
|
|
|
|
name,
|
|
|
|
vec![
|
|
|
|
ModuleParamType::Input,
|
|
|
|
ModuleParamType::Input,
|
|
|
|
ModuleParamType::Output,
|
|
|
|
],
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn intern_module(&mut self) -> Option<InternalModule> {
|
|
|
|
let name = self
|
|
|
|
.consume(
|
|
|
|
TokenType::Identifier,
|
|
|
|
"Expected module name after 'module'.",
|
|
|
|
)?
|
|
|
|
.lexeme;
|
|
|
|
self.consume(TokenType::LeftParen, "Expected '(' after module name.")?;
|
|
|
|
|
|
|
|
// Get parameters
|
|
|
|
let mut params = Vec::new();
|
|
|
|
if self.peek().token_type != TokenType::RightParen {
|
|
|
|
let mut another = true;
|
|
|
|
while !self.is_at_end() && another {
|
|
|
|
let param_type = self.consume_any(
|
|
|
|
&[TokenType::Input, TokenType::Output],
|
|
|
|
"Expected signal direction declaration in module definition.",
|
|
|
|
)?;
|
|
|
|
let param_name = self.consume(TokenType::Identifier, "Expected signal name.")?;
|
|
|
|
let module_param = if self.match_type(TokenType::LeftBracket).is_some() {
|
|
|
|
let start_index = self.consume_number("Expected start index for bus.")?;
|
|
|
|
self.consume(
|
|
|
|
TokenType::Colon,
|
|
|
|
"Expected ':' between start and end index.",
|
|
|
|
)?;
|
|
|
|
let end_index = self.consume_number("Expected end index for bus.")?;
|
|
|
|
self.consume(TokenType::RightBracket, "Expected ']'.")?;
|
|
|
|
|
|
|
|
ModuleParam::new_bus(¶m_type, param_name, start_index, end_index)
|
|
|
|
} else {
|
|
|
|
ModuleParam::new(¶m_type, param_name)
|
|
|
|
};
|
|
|
|
params.push(module_param);
|
|
|
|
another = self.match_type(TokenType::Comma).is_some();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.consume(
|
|
|
|
TokenType::RightParen,
|
|
|
|
"Expected ')' after module parameters.",
|
|
|
|
)?;
|
|
|
|
|
|
|
|
self.consume(TokenType::LeftBrace, "Expected '{' before module body.")?;
|
|
|
|
|
|
|
|
let mut stmts = Vec::new();
|
|
|
|
|
|
|
|
while self.peek().token_type != TokenType::RightBrace {
|
|
|
|
stmts.push(self.statement()?);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.consume(TokenType::RightBrace, "Expected '}' after module body.");
|
|
|
|
|
|
|
|
Some(InternalModule::new(name, params, stmts))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn statement(&mut self) -> Option<Stmt> {
|
|
|
|
let token = self.advance();
|
|
|
|
let ret = match token.token_type {
|
|
|
|
TokenType::Signal => {
|
|
|
|
let name = self
|
|
|
|
.consume(TokenType::Identifier, "Expected identifier after 'signal'.")?
|
|
|
|
.lexeme;
|
|
|
|
if self.match_type(TokenType::LeftBracket).is_some() {
|
|
|
|
let start_index = self.consume_number("Expected start index for bus.")?;
|
|
|
|
self.consume(
|
|
|
|
TokenType::Colon,
|
|
|
|
"Expected ':' between start and end index.",
|
|
|
|
)?;
|
|
|
|
let end_index = self.consume_number("Expected end index for bus.")?;
|
|
|
|
self.consume(TokenType::RightBracket, "Expected ']'.")?;
|
|
|
|
Stmt::new_bus(name, start_index, end_index)
|
|
|
|
} else {
|
|
|
|
Stmt::new_signal(name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TokenType::Identifier => self.call(token.lexeme)?,
|
|
|
|
_ => {
|
|
|
|
self.error_handler.error_token(&token, "Unexpected token.");
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
self.consume(TokenType::Semicolon, "Expected ';' after statement.")?;
|
|
|
|
|
|
|
|
Some(ret)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn call(&mut self, name: String) -> Option<Stmt> {
|
|
|
|
self.consume(TokenType::LeftParen, "Expected '(' after identifier.")?;
|
|
|
|
|
|
|
|
let mut args = Vec::new();
|
|
|
|
if self.peek().token_type != TokenType::RightParen {
|
|
|
|
let mut another = true;
|
|
|
|
while !self.is_at_end() && another {
|
|
|
|
let connection_name = self
|
|
|
|
.consume(
|
|
|
|
TokenType::Identifier,
|
|
|
|
"Expected identifier for module argument.",
|
|
|
|
)?
|
|
|
|
.lexeme;
|
|
|
|
let conn = if self.match_type(TokenType::LeftBracket).is_some() {
|
|
|
|
let index = self.consume_number("Expected number after '['.")?;
|
|
|
|
let c = if self.match_type(TokenType::Colon).is_some() {
|
|
|
|
let end_index = self.consume_number("Expected number after ':'.")?;
|
|
|
|
Connection::new_bus_from_bus(connection_name, index, end_index)
|
|
|
|
} else {
|
|
|
|
Connection::new_signal_from_bus(connection_name, index)
|
|
|
|
};
|
|
|
|
|
|
|
|
self.consume(TokenType::RightBracket, "Expected ']'.")?;
|
|
|
|
|
|
|
|
c
|
|
|
|
} else {
|
|
|
|
Connection::new_signal_from_signal(connection_name)
|
|
|
|
};
|
|
|
|
|
|
|
|
args.push(conn);
|
|
|
|
|
|
|
|
another = self.match_type(TokenType::Comma).is_some();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.consume(TokenType::RightParen, "Expected ')' after argument list.")?;
|
|
|
|
|
|
|
|
Some(Stmt::new_call(name, args))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn synchronize(&mut self) {
|
|
|
|
self.advance();
|
|
|
|
while !self.is_at_end() {
|
|
|
|
if self.peek().token_type == TokenType::Module {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.advance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_at_end(&self) -> bool {
|
|
|
|
self.peek().token_type == TokenType::Eof
|
|
|
|
}
|
|
|
|
|
|
|
|
fn peek(&self) -> Token {
|
|
|
|
self.tokens[self.current].clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn match_type(&mut self, token_type: TokenType) -> Option<Token> {
|
|
|
|
if self.check(&token_type) {
|
|
|
|
Some(self.advance())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check(&self, token_type: &TokenType) -> bool {
|
|
|
|
if self.is_at_end() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
&self.peek().token_type == token_type
|
|
|
|
}
|
|
|
|
|
|
|
|
fn advance(&mut self) -> Token {
|
|
|
|
let token = self.peek();
|
|
|
|
if !self.is_at_end() {
|
|
|
|
self.current += 1;
|
|
|
|
}
|
|
|
|
token
|
|
|
|
}
|
|
|
|
|
|
|
|
fn consume(&mut self, token_type: TokenType, message: &str) -> Option<Token> {
|
|
|
|
if self.check(&token_type) {
|
|
|
|
Some(self.advance())
|
|
|
|
} else {
|
|
|
|
self.error_handler.error_token(&self.peek(), message);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn consume_any(&mut self, types: &[TokenType], message: &str) -> Option<Token> {
|
|
|
|
for t in types {
|
|
|
|
if self.check(&t) {
|
|
|
|
return Some(self.advance());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.error_handler.error_token(&self.peek(), message);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn consume_string(&mut self, message: &str) -> Option<Token> {
|
|
|
|
if let TokenType::String(_) = self.peek().token_type {
|
|
|
|
Some(self.advance())
|
|
|
|
} else {
|
|
|
|
self.error_handler.error_token(&self.peek(), message);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn consume_number(&mut self, message: &str) -> Option<i32> {
|
|
|
|
if let TokenType::Number(num) = self.peek().token_type {
|
|
|
|
self.advance();
|
|
|
|
Some(num)
|
|
|
|
} else {
|
|
|
|
self.error_handler.error_token(&self.peek(), message);
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|