summaryrefslogtreecommitdiff
path: root/src/stages
diff options
context:
space:
mode:
Diffstat (limited to 'src/stages')
-rw-r--r--src/stages/bytecode.rs24
-rw-r--r--src/stages/semantic.rs21
-rw-r--r--src/stages/semantic_tokens.rs9
-rw-r--r--src/stages/syntactic.rs21
-rw-r--r--src/stages/syntactic_tokens.rs2
5 files changed, 38 insertions, 39 deletions
diff --git a/src/stages/bytecode.rs b/src/stages/bytecode.rs
index 6878c42..02cc739 100644
--- a/src/stages/bytecode.rs
+++ b/src/stages/bytecode.rs
@@ -1,6 +1,6 @@
use crate::*;
-use std::collections::HashMap;
+use indexmap::IndexMap;
/// Doesn't truncate trailing null bytes.
@@ -14,22 +14,16 @@ pub fn generate_bytecode(semantic: &Program) -> Result<AssembledProgram, Vec<Tra
let address = information.address;
symbols.push(AssembledSymbol { name, address, source });
}
-
match generator.errors.is_empty() {
- true => Ok(
- AssembledProgram {
- bytecode: generator.bytecode,
- symbols,
- }
- ),
+ true => Ok(AssembledProgram { bytecode: generator.bytecode, symbols }),
false => Err(generator.errors),
}
}
pub struct BytecodeGenerator<'a> {
- definitions: &'a HashMap<String, Tracked<Definition>>,
- labels: HashMap<String, LabelInformation>,
+ definitions: &'a IndexMap<String, Tracked<Definition>>,
+ labels: IndexMap<String, LabelInformation>,
stack: Vec<usize>,
bytecode: Vec<u8>,
errors: Vec<Tracked<BytecodeError>>,
@@ -41,8 +35,8 @@ struct LabelInformation {
}
impl<'a> BytecodeGenerator<'a> {
- pub fn new(definitions: &'a HashMap<String, Tracked<Definition>>) -> Self {
- let mut labels = HashMap::new();
+ pub fn new(definitions: &'a IndexMap<String, Tracked<Definition>>) -> Self {
+ let mut labels = IndexMap::new();
for (name, definition) in definitions {
if let DefinitionVariant::LabelDefinition = definition.variant {
// Use fake address for now.
@@ -61,9 +55,7 @@ impl<'a> BytecodeGenerator<'a> {
pub fn parse(&mut self, tokens: &[Tracked<SemanticToken>], in_macro: bool) {
macro_rules! byte {
- ($byte:expr) => {
- self.bytecode.push($byte)
- };
+ ($byte:expr) => { self.bytecode.push($byte) };
}
macro_rules! double {
($double:expr) => {{
@@ -140,7 +132,7 @@ impl<'a> BytecodeGenerator<'a> {
}
}
- if !self.stack.is_empty() {
+ if !in_macro && !self.stack.is_empty() {
unreachable!("Uncaught unterminated block");
}
}
diff --git a/src/stages/semantic.rs b/src/stages/semantic.rs
index f2774a4..dc9709e 100644
--- a/src/stages/semantic.rs
+++ b/src/stages/semantic.rs
@@ -1,15 +1,24 @@
use crate::*;
-use std::collections::{HashMap, HashSet};
+use std::str::FromStr;
+
+use indexmap::{IndexMap, IndexSet};
pub fn parse_semantic(syntactic: Vec<Tracked<SyntacticToken>>) -> Result<Program, Vec<Tracked<SemanticError>>> {
+ let mut errors = Vec::new();
+
// Record all label definitions and macro names up front.
- let mut definitions = HashMap::new();
- let mut macro_names = HashSet::new();
+ let mut definitions = IndexMap::new();
+ let mut macro_names = IndexSet::new();
for token in &syntactic {
match &token.value {
SyntacticToken::LabelDefinition(name) => {
+ // Check if identifier is reserved.
+ if Instruction::from_str(&name).is_ok() {
+ let error = SemanticError::ReservedIdentifier(name.to_string());
+ errors.push(Tracked::from(error, token.source.clone()));
+ }
// Use a fake index for now.
let definition = Definition::new(0, DefinitionVariant::LabelDefinition);
let tracked = Tracked::from(definition, token.source.clone());
@@ -19,6 +28,11 @@ pub fn parse_semantic(syntactic: Vec<Tracked<SyntacticToken>>) -> Result<Program
}
SyntacticToken::MacroDefinition(definition) => {
let name = &definition.name;
+ // Check if identifier is reserved.
+ if Instruction::from_str(&name).is_ok() {
+ let error = SemanticError::ReservedIdentifier(name.to_string());
+ errors.push(Tracked::from(error, name.source.clone()));
+ }
if !macro_names.insert(name.clone()) {
unreachable!("Uncaught duplicate macro definition '{name}'")
}
@@ -29,7 +43,6 @@ pub fn parse_semantic(syntactic: Vec<Tracked<SyntacticToken>>) -> Result<Program
// Convert syntactic tokens to semantic tokens.
let mut tokens: Vec<Tracked<SemanticToken>> = Vec::new();
- let mut errors = Vec::new();
let mut stack = Vec::new();
for syn_token in syntactic {
diff --git a/src/stages/semantic_tokens.rs b/src/stages/semantic_tokens.rs
index fe49c26..c735828 100644
--- a/src/stages/semantic_tokens.rs
+++ b/src/stages/semantic_tokens.rs
@@ -1,10 +1,10 @@
use crate::*;
-use std::collections::HashMap;
+use indexmap::IndexMap;
pub struct Program {
- pub definitions: HashMap<String, Tracked<Definition>>,
+ pub definitions: IndexMap<String, Tracked<Definition>>,
pub tokens: Vec<Tracked<SemanticToken>>,
}
@@ -49,6 +49,7 @@ pub enum SemanticToken {
pub enum SemanticError {
InvocationBeforeDefinition,
+ ReservedIdentifier(String),
}
@@ -64,12 +65,14 @@ fn report_semantic_error(error: &Tracked<SemanticError>, source_code: &str) {
let message = match &error.value {
SemanticError::InvocationBeforeDefinition =>
"Macro cannot be invoked before it has been defined",
+ SemanticError::ReservedIdentifier(name) =>
+ &format!("Identifier '{name}' is reserved for a built-in instruction"),
};
report_source_issue(LogLevel::Error, &context, message);
}
-pub fn print_semantic_token(i: usize, token: &SemanticToken, definitions: &HashMap<String, Tracked<Definition>>) {
+pub fn print_semantic_token(i: usize, token: &SemanticToken, definitions: &IndexMap<String, Tracked<Definition>>) {
match token {
SemanticToken::Literal(value) => indent!(i, "Literal({value})"),
SemanticToken::Pad(value) => indent!(i, "Pad({value})"),
diff --git a/src/stages/syntactic.rs b/src/stages/syntactic.rs
index 6453ae0..59b8b95 100644
--- a/src/stages/syntactic.rs
+++ b/src/stages/syntactic.rs
@@ -37,7 +37,7 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
}
// Eat characters until the end character is found.
- macro_rules! is_any_end {
+ macro_rules! is_end {
($end:expr) => {
|t: &mut Tokeniser| {
t.eat_char() == Some($end)
@@ -45,15 +45,6 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
};
}
- // Eat characters until the end character is found without a preceding back-slash.
- macro_rules! is_plain_end {
- ($end:expr) => {
- |t: &mut Tokeniser| {
- t.eat_if(concat!('\\', $end)).is_some() || t.eat_char() == Some($end)
- }
- };
- }
-
loop {
// Eat leading whitespace.
while let Some(c) = t.peek_char() {
@@ -67,7 +58,7 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
let token = match c {
'"' => {
let source = t.get_source();
- match t.track_until(is_plain_end!('"')) {
+ match t.track_until(is_end!('"')) {
Some(string) => {
let mut bytes = string.into_bytes();
bytes.push(0x00);
@@ -78,14 +69,14 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
}
'\'' => {
let source = t.get_source();
- match t.track_until(is_plain_end!('\'')) {
+ match t.track_until(is_end!('\'')) {
Some(string) => SyntacticToken::String(string.into_bytes()),
None => err!(SyntacticError::UnterminatedRawString, source),
}
}
'(' => {
let source = t.get_source();
- if let Some(string) = t.track_until(is_any_end!(')')) {
+ if let Some(string) = t.track_until(is_end!(')')) {
// Check if the comment fills the entire line.
if t.start.position.column == 0 && t.end_of_line() {
if let Some(path) = string.strip_prefix(": ") {
@@ -105,7 +96,7 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
let source = t.get_source();
check_name!(name, source);
t.mark_child();
- if let Some(_) = t.track_until(is_any_end!(';')) {
+ if let Some(_) = t.track_until(is_end!(';')) {
let child = t.tokenise_child_span();
match parse_body_from_tokeniser(child, &label_name) {
Ok(body) => {
@@ -149,7 +140,7 @@ fn parse_syntactic_from_tokeniser(mut t: Tokeniser, label_name: &str) -> Result<
}
},
':' => {
- SyntacticToken::Symbol(String::from(':'))
+ SyntacticToken::Instruction(Instruction { value: 0x21 })
}
c => {
let token = format!("{c}{}", t.eat_token());
diff --git a/src/stages/syntactic_tokens.rs b/src/stages/syntactic_tokens.rs
index 2a95967..35afa80 100644
--- a/src/stages/syntactic_tokens.rs
+++ b/src/stages/syntactic_tokens.rs
@@ -80,7 +80,7 @@ pub fn print_syntactic_token(i: usize, token: &SyntacticToken) {
SyntacticToken::String(bytes) => indent!(i, "String({})", String::from_utf8_lossy(bytes)),
SyntacticToken::Comment(_) => indent!(i, "Comment"),
SyntacticToken::BlockOpen => indent!(i, "BlockOpen"),
- SyntacticToken::BlockClose => indent!(i, "BlockOpen"),
+ SyntacticToken::BlockClose => indent!(i, "BlockClose"),
SyntacticToken::Symbol(name) => indent!(i, "Symbol({name})"),
SyntacticToken::Instruction(instruction) => indent!(i, "Instruction({instruction})"),
SyntacticToken::LabelDefinition(name) => indent!(i, "LabelDefinition({name})"),