use crate::{
compilation::{
CompilationError, Lexer, Parser,
token::{Token, TokenKind},
},
execution::{Chunk, op_code::OpCode},
scripting_value::ScriptingValue,
};
use super::PrefixParselet;
#[derive(Clone)]
pub struct AssignmentParselet;
impl PrefixParselet for AssignmentParselet {
fn parse(
&self,
lexer: &mut Lexer,
parser: &mut Parser,
chunk: &mut Chunk,
token: Token,
) -> Result<(), CompilationError> {
let next = parser.next();
match next.kind {
TokenKind::ColonEqual => {
parser.advance(lexer)?;
parser.expression(lexer, chunk)?;
let name = chunk.add_constant(ScriptingValue::String(token.origin))?;
parser.emit_bytes(OpCode::DefineExternal as u8, name, chunk);
}
TokenKind::PlusEqual => {
let name = chunk.add_constant(ScriptingValue::String(token.origin))?;
parser.emit_bytes(OpCode::GetExternal as u8, name, chunk);
parser.advance(lexer)?;
parser.expression(lexer, chunk)?;
parser.emit_byte(OpCode::Add as u8, chunk);
parser.emit_bytes(OpCode::SetExternal as u8, name, chunk);
}
TokenKind::MinusEqual => {
let name = chunk.add_constant(ScriptingValue::String(token.origin))?;
parser.emit_bytes(OpCode::GetExternal as u8, name, chunk);
parser.advance(lexer)?;
parser.expression(lexer, chunk)?;
parser.emit_byte(OpCode::Subtract as u8, chunk);
parser.emit_bytes(OpCode::SetExternal as u8, name, chunk);
}
TokenKind::StarEqual => {
let name = chunk.add_constant(ScriptingValue::String(token.origin))?;
parser.emit_bytes(OpCode::GetExternal as u8, name, chunk);
parser.advance(lexer)?;
parser.expression(lexer, chunk)?;
parser.emit_byte(OpCode::Multiply as u8, chunk);
parser.emit_bytes(OpCode::SetExternal as u8, name, chunk);
}
TokenKind::SlashEqual => {
let name = chunk.add_constant(ScriptingValue::String(token.origin))?;
parser.emit_bytes(OpCode::GetExternal as u8, name, chunk);
parser.advance(lexer)?;
parser.expression(lexer, chunk)?;
parser.emit_byte(OpCode::Divide as u8, chunk);
parser.emit_bytes(OpCode::SetExternal as u8, name, chunk);
}
TokenKind::Equal => {
parser.advance(lexer)?;
parser.expression(lexer, chunk)?;
let name = chunk.add_constant(ScriptingValue::String(token.origin))?;
parser.emit_bytes(OpCode::SetExternal as u8, name, chunk);
}
_ => {
let name = chunk.add_constant(ScriptingValue::String(token.origin))?;
parser.emit_bytes(OpCode::GetExternal as u8, name, chunk);
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
const fn is_normal<T: Sized + Send + Sync>() {}
#[test]
const fn normal_types() {
is_normal::<&AssignmentParselet>();
is_normal::<AssignmentParselet>();
}
}