Add support for device declaration expressions
This commit is contained in:
@@ -35,6 +35,7 @@ pub struct Compiler<'a> {
|
|||||||
/// Max stack size for the program is by default 512.
|
/// Max stack size for the program is by default 512.
|
||||||
variable_scope: Vec<HashMap<String, i32>>,
|
variable_scope: Vec<HashMap<String, i32>>,
|
||||||
function_locations: HashMap<String, usize>,
|
function_locations: HashMap<String, usize>,
|
||||||
|
devices: HashMap<String, String>,
|
||||||
output: &'a mut BufWriter<Box<dyn Write>>,
|
output: &'a mut BufWriter<Box<dyn Write>>,
|
||||||
current_line: usize,
|
current_line: usize,
|
||||||
declared_main: bool,
|
declared_main: bool,
|
||||||
@@ -46,6 +47,7 @@ impl<'a> Compiler<'a> {
|
|||||||
parser,
|
parser,
|
||||||
variable_scope: Vec::new(),
|
variable_scope: Vec::new(),
|
||||||
function_locations: HashMap::new(),
|
function_locations: HashMap::new(),
|
||||||
|
devices: HashMap::new(),
|
||||||
output: writer,
|
output: writer,
|
||||||
current_line: 0,
|
current_line: 0,
|
||||||
declared_main: false,
|
declared_main: false,
|
||||||
@@ -122,6 +124,12 @@ impl<'a> Compiler<'a> {
|
|||||||
Expression::DeclarationExpression(var_name, expr) => {
|
Expression::DeclarationExpression(var_name, expr) => {
|
||||||
self.declaration_expression(&var_name, *expr)?
|
self.declaration_expression(&var_name, *expr)?
|
||||||
}
|
}
|
||||||
|
Expression::DeviceDeclarationExpression(DeviceDeclarationExpression {
|
||||||
|
name,
|
||||||
|
device,
|
||||||
|
}) => {
|
||||||
|
self.devices.insert(name, device);
|
||||||
|
}
|
||||||
_ => todo!("{:?}", expression),
|
_ => todo!("{:?}", expression),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -250,7 +258,7 @@ impl<'a> Compiler<'a> {
|
|||||||
}
|
}
|
||||||
_ => todo!("something is up with the arguments"),
|
_ => todo!("something is up with the arguments"),
|
||||||
}
|
}
|
||||||
self.push_stack(&format!("{function_name}{iter_index}"))?;
|
self.push_stack(&format!("{function_name}Invocation{iter_index}"))?;
|
||||||
|
|
||||||
iter_index += 1;
|
iter_index += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,6 +180,10 @@ impl Parser {
|
|||||||
// match declarations with a `let` keyword
|
// match declarations with a `let` keyword
|
||||||
TokenType::Keyword(Keyword::Let) => self.declaration()?,
|
TokenType::Keyword(Keyword::Let) => self.declaration()?,
|
||||||
|
|
||||||
|
TokenType::Keyword(Keyword::Device) => {
|
||||||
|
Expression::DeviceDeclarationExpression(self.device()?)
|
||||||
|
}
|
||||||
|
|
||||||
// match functions with a `fn` keyword
|
// match functions with a `fn` keyword
|
||||||
TokenType::Keyword(Keyword::Fn) => Expression::FunctionExpression(self.function()?),
|
TokenType::Keyword(Keyword::Fn) => Expression::FunctionExpression(self.function()?),
|
||||||
|
|
||||||
@@ -258,6 +262,37 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn device(&mut self) -> Result<DeviceDeclarationExpression, ParseError> {
|
||||||
|
// sanity check, make sure current token is a `device` keyword
|
||||||
|
|
||||||
|
let current_token = token_from_option!(self.current_token);
|
||||||
|
if !self_matches_current!(self, TokenType::Keyword(Keyword::Device)) {
|
||||||
|
return Err(ParseError::UnexpectedToken(current_token.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let identifier = extract_token_data!(
|
||||||
|
token_from_option!(self.get_next()?),
|
||||||
|
TokenType::Identifier(ref id),
|
||||||
|
id.clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
let current_token = token_from_option!(self.get_next()?).clone();
|
||||||
|
if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) {
|
||||||
|
return Err(ParseError::UnexpectedToken(current_token));
|
||||||
|
}
|
||||||
|
|
||||||
|
let device = extract_token_data!(
|
||||||
|
token_from_option!(self.get_next()?),
|
||||||
|
TokenType::String(ref id),
|
||||||
|
id.clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(DeviceDeclarationExpression {
|
||||||
|
name: identifier,
|
||||||
|
device,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn assignment(&mut self) -> Result<AssignmentExpression, ParseError> {
|
fn assignment(&mut self) -> Result<AssignmentExpression, ParseError> {
|
||||||
let identifier = extract_token_data!(
|
let identifier = extract_token_data!(
|
||||||
token_from_option!(self.current_token),
|
token_from_option!(self.current_token),
|
||||||
|
|||||||
@@ -144,6 +144,20 @@ pub enum LiteralOrVariable {
|
|||||||
Variable(String),
|
Variable(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct DeviceDeclarationExpression {
|
||||||
|
/// any variable-like name
|
||||||
|
pub name: String,
|
||||||
|
/// The device port, ex. (db, d0, d1, d2, d3, d4, d5)
|
||||||
|
pub device: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for DeviceDeclarationExpression {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "(device {} = {})", self.name, self.device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
@@ -159,6 +173,7 @@ pub enum Expression {
|
|||||||
PriorityExpression(Box<Expression>),
|
PriorityExpression(Box<Expression>),
|
||||||
ReturnExpression(Box<Expression>),
|
ReturnExpression(Box<Expression>),
|
||||||
Variable(String),
|
Variable(String),
|
||||||
|
DeviceDeclarationExpression(DeviceDeclarationExpression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Expression {
|
impl std::fmt::Display for Expression {
|
||||||
@@ -176,6 +191,7 @@ impl std::fmt::Display for Expression {
|
|||||||
Expression::Variable(id) => write!(f, "{}", id),
|
Expression::Variable(id) => write!(f, "{}", id),
|
||||||
Expression::PriorityExpression(e) => write!(f, "({})", e),
|
Expression::PriorityExpression(e) => write!(f, "({})", e),
|
||||||
Expression::ReturnExpression(e) => write!(f, "(return {})", e),
|
Expression::ReturnExpression(e) => write!(f, "(return {})", e),
|
||||||
|
Expression::DeviceDeclarationExpression(e) => write!(f, "{}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -406,6 +406,7 @@ impl Tokenizer {
|
|||||||
"enum" if next_ws!() => keyword!(Enum),
|
"enum" if next_ws!() => keyword!(Enum),
|
||||||
"import" if next_ws!() => keyword!(Import),
|
"import" if next_ws!() => keyword!(Import),
|
||||||
"export" if next_ws!() => keyword!(Export),
|
"export" if next_ws!() => keyword!(Export),
|
||||||
|
"device" if next_ws!() => keyword!(Device),
|
||||||
|
|
||||||
// boolean literals
|
// boolean literals
|
||||||
"true" if next_ws!() => {
|
"true" if next_ws!() => {
|
||||||
|
|||||||
@@ -164,6 +164,8 @@ pub enum Keyword {
|
|||||||
Fn,
|
Fn,
|
||||||
/// Represents the `if` keyword
|
/// Represents the `if` keyword
|
||||||
If,
|
If,
|
||||||
|
/// Represents the `device` keyword. Useful for defining a device at a specific address (ex. d0, d1, d2, etc.)
|
||||||
|
Device,
|
||||||
/// Represents the `else` keyword
|
/// Represents the `else` keyword
|
||||||
Else,
|
Else,
|
||||||
/// Represents the `return` keyword
|
/// Represents the `return` keyword
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
device self = "db";
|
||||||
|
|
||||||
fn doStuff(x, y, z) {
|
fn doStuff(x, y, z) {
|
||||||
let i = x + y + z;
|
let i = x + y + z;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user