parser and tree nodes seem to be working. Need to fix compiler
This commit is contained in:
@@ -5,7 +5,7 @@ use parser::{
|
|||||||
tree_node::{
|
tree_node::{
|
||||||
AssignmentExpression, BinaryExpression, BlockExpression, DeviceDeclarationExpression,
|
AssignmentExpression, BinaryExpression, BlockExpression, DeviceDeclarationExpression,
|
||||||
Expression, FunctionExpression, IfExpression, InvocationExpression, Literal,
|
Expression, FunctionExpression, IfExpression, InvocationExpression, Literal,
|
||||||
LiteralOrVariable, LogicalExpression, LoopExpression, WhileExpression,
|
LiteralOrVariable, LogicalExpression, LoopExpression, Span, Spanned, WhileExpression,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use quick_error::quick_error;
|
use quick_error::quick_error;
|
||||||
@@ -22,6 +22,14 @@ macro_rules! debug {
|
|||||||
"".into()
|
"".into()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
($self: expr, $debug_value: expr, $args: expr) => {
|
||||||
|
if $self.config.debug {
|
||||||
|
format!($debug_value, $args)
|
||||||
|
} else {
|
||||||
|
"".into()
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
quick_error! {
|
quick_error! {
|
||||||
@@ -36,19 +44,19 @@ quick_error! {
|
|||||||
ScopeError(error: variable_manager::Error) {
|
ScopeError(error: variable_manager::Error) {
|
||||||
from()
|
from()
|
||||||
}
|
}
|
||||||
DuplicateIdentifier(func_name: String) {
|
DuplicateIdentifier(func_name: String, span: Span) {
|
||||||
display("`{func_name}` has already been defined")
|
display("`{func_name}` has already been defined")
|
||||||
}
|
}
|
||||||
UnknownIdentifier(ident: String) {
|
UnknownIdentifier(ident: String, span: Span) {
|
||||||
display("`{ident}` is not found in the current scope.")
|
display("`{ident}` is not found in the current scope.")
|
||||||
}
|
}
|
||||||
InvalidDevice(device: String) {
|
InvalidDevice(device: String, span: Span) {
|
||||||
display("`{device}` is not valid")
|
display("`{device}` is not valid")
|
||||||
}
|
}
|
||||||
AgrumentMismatch(func_name: String) {
|
AgrumentMismatch(func_name: String, span: Span) {
|
||||||
display("Incorrect number of arguments passed into `{func_name}`")
|
display("Incorrect number of arguments passed into `{func_name}`")
|
||||||
}
|
}
|
||||||
Unknown(reason: String) {
|
Unknown(reason: String, span: Option<Span>) {
|
||||||
display("{reason}")
|
display("{reason}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +181,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
Expression::Declaration(var_name, expr) => {
|
Expression::Declaration(var_name, expr) => {
|
||||||
self.expression_declaration(var_name, *expr, scope)
|
self.expression_declaration(var_name.node, *expr, scope)
|
||||||
}
|
}
|
||||||
Expression::Assignment(assign_expr) => {
|
Expression::Assignment(assign_expr) => {
|
||||||
self.expression_assignment(assign_expr, scope)?;
|
self.expression_assignment(assign_expr, scope)?;
|
||||||
@@ -223,7 +231,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Expression::Variable(name) => {
|
Expression::Variable(name) => {
|
||||||
let loc = scope.get_location_of(&name)?;
|
let loc = scope.get_location_of(&name.node)?;
|
||||||
Ok(Some(CompilationResult {
|
Ok(Some(CompilationResult {
|
||||||
location: loc,
|
location: loc,
|
||||||
temp_name: None, // User variable, do not free
|
temp_name: None, // User variable, do not free
|
||||||
@@ -368,7 +376,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
(var_loc, None)
|
(var_loc, None)
|
||||||
}
|
}
|
||||||
Expression::Variable(name) => {
|
Expression::Variable(name) => {
|
||||||
let src_loc = scope.get_location_of(&name)?;
|
let src_loc = scope.get_location_of(&name.node)?;
|
||||||
let var_loc = scope.add_variable(&var_name, LocationRequest::Persist)?;
|
let var_loc = scope.add_variable(&var_name, LocationRequest::Persist)?;
|
||||||
|
|
||||||
// Handle loading from stack if necessary
|
// Handle loading from stack if necessary
|
||||||
@@ -417,11 +425,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
expression,
|
expression,
|
||||||
} = expr;
|
} = expr;
|
||||||
|
|
||||||
let location = scope.get_location_of(&identifier)?;
|
let location = scope.get_location_of(&identifier.node)?;
|
||||||
let (val_str, cleanup) = self.compile_operand(*expression, scope)?;
|
let (val_str, cleanup) = self.compile_operand(*expression, scope)?;
|
||||||
|
|
||||||
let debug_tag = if self.config.debug {
|
let debug_tag = if self.config.debug {
|
||||||
format!(" #{}", identifier)
|
format!(" #{}", identifier.node)
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
@@ -456,16 +464,16 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
invoke_expr: InvocationExpression,
|
invoke_expr: InvocationExpression,
|
||||||
stack: &mut VariableScope,
|
stack: &mut VariableScope,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if !self.function_locations.contains_key(&invoke_expr.name) {
|
if !self.function_locations.contains_key(&invoke_expr.name.node) {
|
||||||
return Err(Error::UnknownIdentifier(invoke_expr.name));
|
return Err(Error::UnknownIdentifier(invoke_expr.name.node));
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(args) = self.function_metadata.get(&invoke_expr.name) else {
|
let Some(args) = self.function_metadata.get(&invoke_expr.name.node) else {
|
||||||
return Err(Error::UnknownIdentifier(invoke_expr.name));
|
return Err(Error::UnknownIdentifier(invoke_expr.name.node));
|
||||||
};
|
};
|
||||||
|
|
||||||
if args.len() != invoke_expr.arguments.len() {
|
if args.len() != invoke_expr.arguments.len() {
|
||||||
return Err(Error::AgrumentMismatch(invoke_expr.name));
|
return Err(Error::AgrumentMismatch(invoke_expr.name.node));
|
||||||
}
|
}
|
||||||
|
|
||||||
// backup all used registers to the stack
|
// backup all used registers to the stack
|
||||||
@@ -484,7 +492,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
let val = if b { "1" } else { "0" };
|
let val = if b { "1" } else { "0" };
|
||||||
self.write_output(format!("push {val}"))?;
|
self.write_output(format!("push {val}"))?;
|
||||||
}
|
}
|
||||||
Expression::Variable(var_name) => match stack.get_location_of(var_name)? {
|
Expression::Variable(var_name) => match stack.get_location_of(var_name.node)? {
|
||||||
VariableLocation::Persistant(reg) | VariableLocation::Temporary(reg) => {
|
VariableLocation::Persistant(reg) | VariableLocation::Temporary(reg) => {
|
||||||
self.write_output(format!("push r{reg}"))?;
|
self.write_output(format!("push r{reg}"))?;
|
||||||
}
|
}
|
||||||
@@ -524,14 +532,14 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
_ => {
|
_ => {
|
||||||
return Err(Error::Unknown(format!(
|
return Err(Error::Unknown(format!(
|
||||||
"Attempted to call `{}` with an unsupported argument type",
|
"Attempted to call `{}` with an unsupported argument type",
|
||||||
invoke_expr.name
|
invoke_expr.name.node
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// jump to the function and store current line in ra
|
// jump to the function and store current line in ra
|
||||||
self.write_output(format!("jal {}", invoke_expr.name))?;
|
self.write_output(format!("jal {}", invoke_expr.name.node))?;
|
||||||
|
|
||||||
for register in active_registers {
|
for register in active_registers {
|
||||||
let VariableLocation::Stack(stack_offset) =
|
let VariableLocation::Stack(stack_offset) =
|
||||||
@@ -557,10 +565,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expression_device(&mut self, expr: DeviceDeclarationExpression) -> Result<(), Error> {
|
fn expression_device(&mut self, expr: DeviceDeclarationExpression) -> Result<(), Error> {
|
||||||
if self.devices.contains_key(&expr.name) {
|
if self.devices.contains_key(&expr.name.node) {
|
||||||
return Err(Error::DuplicateIdentifier(expr.name));
|
return Err(Error::DuplicateIdentifier(expr.name.node));
|
||||||
}
|
}
|
||||||
self.devices.insert(expr.name, expr.device);
|
self.devices.insert(expr.name.node, expr.device);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -589,7 +597,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
|
|
||||||
// Compile Body
|
// Compile Body
|
||||||
// Scope variables in body are ephemeral to the block, handled by expression_block
|
// Scope variables in body are ephemeral to the block, handled by expression_block
|
||||||
self.expression_block(expr.body, scope)?;
|
self.expression_block(expr.body.node, scope)?;
|
||||||
|
|
||||||
// If we have an else branch, we need to jump over it after the 'if' body
|
// If we have an else branch, we need to jump over it after the 'if' body
|
||||||
if expr.else_branch.is_some() {
|
if expr.else_branch.is_some() {
|
||||||
@@ -597,8 +605,8 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
self.write_output(format!("{else_label}:"))?;
|
self.write_output(format!("{else_label}:"))?;
|
||||||
|
|
||||||
match *expr.else_branch.unwrap() {
|
match *expr.else_branch.unwrap() {
|
||||||
Expression::Block(block) => self.expression_block(block, scope)?,
|
Expression::Block(block) => self.expression_block(block.node, scope)?,
|
||||||
Expression::If(if_expr) => self.expression_if(if_expr, scope)?,
|
Expression::If(if_expr) => self.expression_if(if_expr.node, scope)?,
|
||||||
_ => unreachable!("Parser ensures else branch is Block or If"),
|
_ => unreachable!("Parser ensures else branch is Block or If"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -623,7 +631,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
self.write_output(format!("{start_label}:"))?;
|
self.write_output(format!("{start_label}:"))?;
|
||||||
|
|
||||||
// Compile Body
|
// Compile Body
|
||||||
self.expression_block(expr.body, scope)?;
|
self.expression_block(expr.body.node, scope)?;
|
||||||
|
|
||||||
// Jump back to start
|
// Jump back to start
|
||||||
self.write_output(format!("j {start_label}"))?;
|
self.write_output(format!("j {start_label}"))?;
|
||||||
@@ -887,9 +895,11 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// First, sort the expressions to ensure functions are hoisted
|
// First, sort the expressions to ensure functions are hoisted
|
||||||
expr.0.sort_by(|a, b| {
|
expr.0.sort_by(|a, b| {
|
||||||
if matches!(b, Expression::Function(_)) && matches!(a, Expression::Function(_)) {
|
if matches!(b.node, Expression::Function(_))
|
||||||
|
&& matches!(a.node, Expression::Function(_))
|
||||||
|
{
|
||||||
std::cmp::Ordering::Equal
|
std::cmp::Ordering::Equal
|
||||||
} else if matches!(a, Expression::Function(_)) {
|
} else if matches!(a.node, Expression::Function(_)) {
|
||||||
std::cmp::Ordering::Less
|
std::cmp::Ordering::Less
|
||||||
} else {
|
} else {
|
||||||
std::cmp::Ordering::Greater
|
std::cmp::Ordering::Greater
|
||||||
@@ -898,19 +908,19 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
|
|
||||||
for expr in expr.0 {
|
for expr in expr.0 {
|
||||||
if !self.declared_main
|
if !self.declared_main
|
||||||
&& !matches!(expr, Expression::Function(_))
|
&& !matches!(expr.node, Expression::Function(_))
|
||||||
&& !scope.has_parent()
|
&& !scope.has_parent()
|
||||||
{
|
{
|
||||||
self.write_output("main:")?;
|
self.write_output("main:")?;
|
||||||
self.declared_main = true;
|
self.declared_main = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
match expr {
|
match expr.node {
|
||||||
Expression::Return(ret_expr) => {
|
Expression::Return(ret_expr) => {
|
||||||
self.expression_return(*ret_expr, scope)?;
|
self.expression_return(*ret_expr, scope)?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let result = self.expression(expr, scope)?;
|
let result = self.expression(expr.node, scope)?;
|
||||||
// If the expression was a statement that returned a temp result (e.g. `1 + 2;` line),
|
// If the expression was a statement that returned a temp result (e.g. `1 + 2;` line),
|
||||||
// we must free it to avoid leaking registers.
|
// we must free it to avoid leaking registers.
|
||||||
if let Some(comp_res) = result
|
if let Some(comp_res) = result
|
||||||
@@ -940,7 +950,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
Expression::Variable(var_name) => match scope.get_location_of(var_name)? {
|
Expression::Variable(var_name) => match scope.get_location_of(var_name.node)? {
|
||||||
VariableLocation::Temporary(reg) | VariableLocation::Persistant(reg) => {
|
VariableLocation::Temporary(reg) | VariableLocation::Persistant(reg) => {
|
||||||
self.write_output(format!(
|
self.write_output(format!(
|
||||||
"move r{} r{reg} {}",
|
"move r{} r{reg} {}",
|
||||||
@@ -1055,8 +1065,8 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(device) = self.devices.get(&device) else {
|
let Some(device) = self.devices.get(&device.node) else {
|
||||||
return Err(Error::InvalidDevice(device));
|
return Err(Error::InvalidDevice(device.node));
|
||||||
};
|
};
|
||||||
|
|
||||||
let Literal::String(logic_type) = logic_type else {
|
let Literal::String(logic_type) = logic_type else {
|
||||||
@@ -1102,8 +1112,8 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(device) = self.devices.get(&device) else {
|
let Some(device) = self.devices.get(&device.node) else {
|
||||||
return Err(Error::InvalidDevice(device));
|
return Err(Error::InvalidDevice(device.node));
|
||||||
};
|
};
|
||||||
|
|
||||||
let Literal::String(logic_type) = logic_type else {
|
let Literal::String(logic_type) = logic_type else {
|
||||||
@@ -1133,27 +1143,29 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
/// Calees are responsible for backing up any registers they wish to use.
|
/// Calees are responsible for backing up any registers they wish to use.
|
||||||
fn expression_function<'v>(
|
fn expression_function<'v>(
|
||||||
&mut self,
|
&mut self,
|
||||||
expr: FunctionExpression,
|
expr: Spanned<FunctionExpression>,
|
||||||
scope: &mut VariableScope<'v>,
|
scope: &mut VariableScope<'v>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let FunctionExpression {
|
let FunctionExpression {
|
||||||
name,
|
name,
|
||||||
arguments,
|
arguments,
|
||||||
body,
|
body,
|
||||||
} = expr;
|
} = *expr;
|
||||||
|
|
||||||
if self.function_locations.contains_key(&name) {
|
if self.function_locations.contains_key(&name.node) {
|
||||||
return Err(Error::DuplicateIdentifier(name));
|
return Err(Error::DuplicateIdentifier(name.node));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.function_metadata
|
self.function_metadata.insert(
|
||||||
.insert(name.clone(), arguments.clone());
|
name.node.clone(),
|
||||||
|
arguments.iter().map(|a| a.node.clone()).collect(),
|
||||||
|
);
|
||||||
|
|
||||||
// Declare the function as a line identifier
|
// Declare the function as a line identifier
|
||||||
self.write_output(format!("{}:", name))?;
|
self.write_output(format!("{}:", name.node))?;
|
||||||
|
|
||||||
self.function_locations
|
self.function_locations
|
||||||
.insert(name.clone(), self.current_line);
|
.insert(name.node.clone(), self.current_line);
|
||||||
|
|
||||||
// Create a new block scope for the function body
|
// Create a new block scope for the function body
|
||||||
let mut block_scope = VariableScope::scoped(scope);
|
let mut block_scope = VariableScope::scoped(scope);
|
||||||
@@ -1166,13 +1178,16 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
.rev()
|
.rev()
|
||||||
.take(VariableScope::PERSIST_REGISTER_COUNT as usize)
|
.take(VariableScope::PERSIST_REGISTER_COUNT as usize)
|
||||||
{
|
{
|
||||||
let loc = block_scope.add_variable(var_name, LocationRequest::Persist)?;
|
let loc = block_scope.add_variable(var_name.node.clone(), LocationRequest::Persist)?;
|
||||||
// we don't need to imcrement the stack offset as it's already on the stack from the
|
// we don't need to imcrement the stack offset as it's already on the stack from the
|
||||||
// previous scope
|
// previous scope
|
||||||
|
|
||||||
match loc {
|
match loc {
|
||||||
VariableLocation::Persistant(loc) => {
|
VariableLocation::Persistant(loc) => {
|
||||||
self.write_output(format!("pop r{loc} {}", debug!(self, "#{var_name}")))?;
|
self.write_output(format!(
|
||||||
|
"pop r{loc} {}",
|
||||||
|
debug!(self, "#{}", var_name.node)
|
||||||
|
))?;
|
||||||
}
|
}
|
||||||
VariableLocation::Stack(_) => {
|
VariableLocation::Stack(_) => {
|
||||||
return Err(Error::Unknown(
|
return Err(Error::Unknown(
|
||||||
@@ -1194,19 +1209,19 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
// anything as they already exist on the stack, but we DO need to let our block_scope be
|
// anything as they already exist on the stack, but we DO need to let our block_scope be
|
||||||
// aware that the variables exist on the stack (left to right)
|
// aware that the variables exist on the stack (left to right)
|
||||||
for var_name in arguments.iter().take(arguments.len() - saved_variables) {
|
for var_name in arguments.iter().take(arguments.len() - saved_variables) {
|
||||||
block_scope.add_variable(var_name, LocationRequest::Stack)?;
|
block_scope.add_variable(var_name.node.clone(), LocationRequest::Stack)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_output("push ra")?;
|
self.write_output("push ra")?;
|
||||||
block_scope.add_variable(format!("{name}_ra"), LocationRequest::Stack)?;
|
block_scope.add_variable(format!("{}_ra", name.node), LocationRequest::Stack)?;
|
||||||
|
|
||||||
for expr in body.0 {
|
for expr in body.0 {
|
||||||
match expr {
|
match expr.node {
|
||||||
Expression::Return(ret_expr) => {
|
Expression::Return(ret_expr) => {
|
||||||
self.expression_return(*ret_expr, &mut block_scope)?;
|
self.expression_return(*ret_expr, &mut block_scope)?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let result = self.expression(expr, &mut block_scope)?;
|
let result = self.expression(expr.node, &mut block_scope)?;
|
||||||
// Free unused statement results
|
// Free unused statement results
|
||||||
if let Some(comp_res) = result
|
if let Some(comp_res) = result
|
||||||
&& let Some(name) = comp_res.temp_name
|
&& let Some(name) = comp_res.temp_name
|
||||||
@@ -1219,7 +1234,7 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
|
|||||||
|
|
||||||
// Get the saved return address and save it back into `ra`
|
// Get the saved return address and save it back into `ra`
|
||||||
let VariableLocation::Stack(ra_stack_offset) =
|
let VariableLocation::Stack(ra_stack_offset) =
|
||||||
block_scope.get_location_of(format!("{name}_ra"))?
|
block_scope.get_location_of(format!("{}_ra", name.node))?
|
||||||
else {
|
else {
|
||||||
return Err(Error::Unknown(
|
return Err(Error::Unknown(
|
||||||
"Stored return address not in stack as expected".into(),
|
"Stored return address not in stack as expected".into(),
|
||||||
|
|||||||
@@ -544,6 +544,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let identifier_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?;
|
let identifier_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?;
|
||||||
|
let identifier_span = Self::token_to_span(identifier_token);
|
||||||
let identifier = match identifier_token.token_type {
|
let identifier = match identifier_token.token_type {
|
||||||
TokenType::Identifier(ref id) => id.clone(),
|
TokenType::Identifier(ref id) => id.clone(),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -574,13 +575,18 @@ impl<'a> Parser<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(DeviceDeclarationExpression {
|
Ok(DeviceDeclarationExpression {
|
||||||
name: identifier,
|
name: Spanned {
|
||||||
|
span: identifier_span,
|
||||||
|
node: identifier,
|
||||||
|
},
|
||||||
device,
|
device,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assignment(&mut self) -> Result<AssignmentExpression, Error> {
|
fn assignment(&mut self) -> Result<AssignmentExpression, Error> {
|
||||||
let identifier = match self.current_token.as_ref().unwrap().token_type {
|
let identifier_token = self.current_token.as_ref().unwrap();
|
||||||
|
let identifier_span = Self::token_to_span(identifier_token);
|
||||||
|
let identifier = match identifier_token.token_type {
|
||||||
TokenType::Identifier(ref id) => id.clone(),
|
TokenType::Identifier(ref id) => id.clone(),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::UnexpectedToken(
|
||||||
@@ -602,7 +608,10 @@ impl<'a> Parser<'a> {
|
|||||||
let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?;
|
let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?;
|
||||||
|
|
||||||
Ok(AssignmentExpression {
|
Ok(AssignmentExpression {
|
||||||
identifier,
|
identifier: Spanned {
|
||||||
|
span: identifier_span,
|
||||||
|
node: identifier,
|
||||||
|
},
|
||||||
expression: boxed!(expression),
|
expression: boxed!(expression),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -905,7 +914,9 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn invocation(&mut self) -> Result<InvocationExpression, Error> {
|
fn invocation(&mut self) -> Result<InvocationExpression, Error> {
|
||||||
let identifier = match self.current_token.as_ref().unwrap().token_type {
|
let identifier_token = self.current_token.as_ref().unwrap();
|
||||||
|
let identifier_span = Self::token_to_span(identifier_token);
|
||||||
|
let identifier = match identifier_token.token_type {
|
||||||
TokenType::Identifier(ref id) => id.clone(),
|
TokenType::Identifier(ref id) => id.clone(),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::UnexpectedToken(
|
||||||
@@ -956,7 +967,10 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(InvocationExpression {
|
Ok(InvocationExpression {
|
||||||
name: identifier,
|
name: Spanned {
|
||||||
|
span: identifier_span,
|
||||||
|
node: identifier,
|
||||||
|
},
|
||||||
arguments,
|
arguments,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1022,13 +1036,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn declaration(&mut self) -> Result<Expression, Error> {
|
fn declaration(&mut self) -> Result<Expression, Error> {
|
||||||
// "let" consumed by unary before calling spanned(declaration).
|
|
||||||
// But spanned() peeks start. Unary did NOT consume let inside unary match...
|
|
||||||
// Wait, Unary DOES match on current_token. It is `Let`.
|
|
||||||
// Then Unary calls `self.spanned(|p| p.declaration())`.
|
|
||||||
// `declaration()` checks `self.current_token` is `Let`.
|
|
||||||
// So `declaration` expects `Let` to be current.
|
|
||||||
|
|
||||||
let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?;
|
let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?;
|
||||||
if !self_matches_current!(self, TokenType::Keyword(Keyword::Let)) {
|
if !self_matches_current!(self, TokenType::Keyword(Keyword::Let)) {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::UnexpectedToken(
|
||||||
@@ -1037,6 +1044,7 @@ impl<'a> Parser<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
let identifier_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?;
|
let identifier_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?;
|
||||||
|
let identifier_span = Self::token_to_span(identifier_token);
|
||||||
let identifier = match identifier_token.token_type {
|
let identifier = match identifier_token.token_type {
|
||||||
TokenType::Identifier(ref id) => id.clone(),
|
TokenType::Identifier(ref id) => id.clone(),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -1068,7 +1076,10 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(Expression::Declaration(
|
Ok(Expression::Declaration(
|
||||||
identifier,
|
Spanned {
|
||||||
|
span: identifier_span,
|
||||||
|
node: identifier,
|
||||||
|
},
|
||||||
boxed!(assignment_expression),
|
boxed!(assignment_expression),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -1210,6 +1221,7 @@ impl<'a> Parser<'a> {
|
|||||||
fn function(&mut self) -> Result<FunctionExpression, Error> {
|
fn function(&mut self) -> Result<FunctionExpression, Error> {
|
||||||
// 'fn' is current
|
// 'fn' is current
|
||||||
let fn_ident_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?;
|
let fn_ident_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?;
|
||||||
|
let fn_ident_span = Self::token_to_span(fn_ident_token);
|
||||||
let fn_ident = match fn_ident_token.token_type {
|
let fn_ident = match fn_ident_token.token_type {
|
||||||
TokenType::Identifier(ref id) => id.clone(),
|
TokenType::Identifier(ref id) => id.clone(),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -1228,13 +1240,14 @@ impl<'a> Parser<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut arguments = Vec::<String>::new();
|
let mut arguments = Vec::<Spanned<String>>::new();
|
||||||
|
|
||||||
while !token_matches!(
|
while !token_matches!(
|
||||||
self.get_next()?.ok_or(Error::UnexpectedEOF)?,
|
self.get_next()?.ok_or(Error::UnexpectedEOF)?,
|
||||||
TokenType::Symbol(Symbol::RParen)
|
TokenType::Symbol(Symbol::RParen)
|
||||||
) {
|
) {
|
||||||
let current_token = self.current_token.as_ref().unwrap();
|
let current_token = self.current_token.as_ref().unwrap();
|
||||||
|
let arg_span = Self::token_to_span(current_token);
|
||||||
let argument = match current_token.token_type {
|
let argument = match current_token.token_type {
|
||||||
TokenType::Identifier(ref id) => id.clone(),
|
TokenType::Identifier(ref id) => id.clone(),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -1245,14 +1258,19 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if arguments.contains(&argument) {
|
let spanned_arg = Spanned {
|
||||||
|
span: arg_span,
|
||||||
|
node: argument,
|
||||||
|
};
|
||||||
|
|
||||||
|
if arguments.contains(&spanned_arg) {
|
||||||
return Err(Error::DuplicateIdentifier(
|
return Err(Error::DuplicateIdentifier(
|
||||||
Self::token_to_span(current_token),
|
Self::token_to_span(current_token),
|
||||||
current_token.clone(),
|
current_token.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments.push(argument);
|
arguments.push(spanned_arg);
|
||||||
|
|
||||||
if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma))
|
if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma))
|
||||||
&& !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen))
|
&& !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen))
|
||||||
@@ -1278,7 +1296,10 @@ impl<'a> Parser<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(FunctionExpression {
|
Ok(FunctionExpression {
|
||||||
name: fn_ident,
|
name: Spanned {
|
||||||
|
span: fn_ident_span,
|
||||||
|
node: fn_ident,
|
||||||
|
},
|
||||||
arguments,
|
arguments,
|
||||||
body: self.block()?,
|
body: self.block()?,
|
||||||
})
|
})
|
||||||
@@ -1305,9 +1326,7 @@ impl<'a> Parser<'a> {
|
|||||||
Some(Expression::Literal(literal)) => {
|
Some(Expression::Literal(literal)) => {
|
||||||
LiteralOrVariable::Literal(literal.node.clone())
|
LiteralOrVariable::Literal(literal.node.clone())
|
||||||
}
|
}
|
||||||
Some(Expression::Variable(ident)) => {
|
Some(Expression::Variable(ident)) => LiteralOrVariable::Variable(ident),
|
||||||
LiteralOrVariable::Variable(ident.node.clone())
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedToken(
|
return Err(Error::UnexpectedToken(
|
||||||
self.current_span(),
|
self.current_span(),
|
||||||
@@ -1334,7 +1353,7 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
let invocation = self.invocation()?;
|
let invocation = self.invocation()?;
|
||||||
|
|
||||||
match invocation.name.as_str() {
|
match invocation.name.node.as_str() {
|
||||||
"yield" => {
|
"yield" => {
|
||||||
check_length(self, &invocation.arguments, 0)?;
|
check_length(self, &invocation.arguments, 0)?;
|
||||||
Ok(SysCall::System(sys_call::System::Yield))
|
Ok(SysCall::System(sys_call::System::Yield))
|
||||||
@@ -1420,3 +1439,4 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ impl std::fmt::Display for LogicalExpression {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct AssignmentExpression {
|
pub struct AssignmentExpression {
|
||||||
pub identifier: String,
|
pub identifier: Spanned<String>,
|
||||||
pub expression: Box<Spanned<Expression>>,
|
pub expression: Box<Spanned<Expression>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,8 +86,8 @@ impl std::fmt::Display for AssignmentExpression {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct FunctionExpression {
|
pub struct FunctionExpression {
|
||||||
pub name: String,
|
pub name: Spanned<String>,
|
||||||
pub arguments: Vec<String>,
|
pub arguments: Vec<Spanned<String>>,
|
||||||
pub body: BlockExpression,
|
pub body: BlockExpression,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,11 @@ impl std::fmt::Display for FunctionExpression {
|
|||||||
f,
|
f,
|
||||||
"(fn {}({}) {{ {} }})",
|
"(fn {}({}) {{ {} }})",
|
||||||
self.name,
|
self.name,
|
||||||
self.arguments.to_vec().join(", "),
|
self.arguments
|
||||||
|
.iter()
|
||||||
|
.map(|e| e.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", "),
|
||||||
self.body
|
self.body
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -122,7 +126,7 @@ impl std::fmt::Display for BlockExpression {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct InvocationExpression {
|
pub struct InvocationExpression {
|
||||||
pub name: String,
|
pub name: Spanned<String>,
|
||||||
pub arguments: Vec<Expression>,
|
pub arguments: Vec<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +148,7 @@ impl std::fmt::Display for InvocationExpression {
|
|||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum LiteralOrVariable {
|
pub enum LiteralOrVariable {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Variable(String),
|
Variable(Spanned<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for LiteralOrVariable {
|
impl std::fmt::Display for LiteralOrVariable {
|
||||||
@@ -159,7 +163,7 @@ impl std::fmt::Display for LiteralOrVariable {
|
|||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct DeviceDeclarationExpression {
|
pub struct DeviceDeclarationExpression {
|
||||||
/// any variable-like name
|
/// any variable-like name
|
||||||
pub name: String,
|
pub name: Spanned<String>,
|
||||||
/// The device port, ex. (db, d0, d1, d2, d3, d4, d5)
|
/// The device port, ex. (db, d0, d1, d2, d3, d4, d5)
|
||||||
pub device: String,
|
pub device: String,
|
||||||
}
|
}
|
||||||
@@ -218,7 +222,7 @@ pub struct Span {
|
|||||||
pub end_col: usize,
|
pub end_col: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Spanned<T> {
|
pub struct Spanned<T> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub node: T,
|
pub node: T,
|
||||||
@@ -248,7 +252,7 @@ pub enum Expression {
|
|||||||
Block(Spanned<BlockExpression>),
|
Block(Spanned<BlockExpression>),
|
||||||
Break(Span),
|
Break(Span),
|
||||||
Continue(Span),
|
Continue(Span),
|
||||||
Declaration(String, Box<Spanned<Expression>>),
|
Declaration(Spanned<String>, Box<Spanned<Expression>>),
|
||||||
DeviceDeclaration(Spanned<DeviceDeclarationExpression>),
|
DeviceDeclaration(Spanned<DeviceDeclarationExpression>),
|
||||||
Function(Spanned<FunctionExpression>),
|
Function(Spanned<FunctionExpression>),
|
||||||
If(Spanned<IfExpression>),
|
If(Spanned<IfExpression>),
|
||||||
@@ -289,3 +293,4 @@ impl std::fmt::Display for Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user