YREA-SLS/SLS_Rust/sls/src/interpreter.rs

135 lines
3.2 KiB
Rust

use std::collections::HashMap;
use crate::lexer::*; // Identifier, Token, TokenString, etc.
use crate::builtin::load_builtins;
pub type BuiltinFn = fn(&mut InterpreterState) -> bool;
#[derive(Debug, Clone)]
pub enum StackValue {
Identifier(Identifier),
I64(i64),
I32(i32),
I16(i16),
I8(i8),
U64(u64),
U32(u32),
U16(u16),
U8(u8),
F32(f32),
F64(f64),
Character(u8),
Boolean(bool),
TokenString(TokenString),
Callable(TokenString),
}
#[derive(Debug, Clone)]
pub enum FunctionItem {
TokenString(TokenString),
Builtin(BuiltinFn),
}
#[derive(Debug)]
pub struct InterpreterState {
pub stack: Vec<StackValue>,
pub functions: HashMap<String, FunctionItem>,
}
impl InterpreterState {
pub fn new() -> Self {
Self {
stack: Vec::new(),
functions: HashMap::new(),
}
}
pub fn init(&mut self) -> bool {
load_builtins(self)
}
pub fn push_token(&mut self, token: &Token) -> bool {
let value = match token {
Token::Eof => return true,
Token::Identifier(id) => {
StackValue::Identifier(id.clone())
}
Token::I64(v) => StackValue::I64(*v),
Token::I32(v) => StackValue::I32(*v),
Token::I16(v) => StackValue::I16(*v),
Token::I8(v) => StackValue::I8(*v),
Token::U64(v) => StackValue::U64(*v),
Token::U32(v) => StackValue::U32(*v),
Token::U16(v) => StackValue::U16(*v),
Token::U8(v) => StackValue::U8(*v),
Token::Float(v) => StackValue::F32(*v),
Token::Double(v) => StackValue::F64(*v),
Token::Character(c) => StackValue::Character(*c),
Token::Boolean(b) => StackValue::Boolean(*b),
Token::TokenString(ts) => StackValue::TokenString(ts.clone()),
Token::StringLiteral(_) |
Token::Array(_) |
Token::TypeTuple(_) => return false,
};
self.stack.push(value);
true
}
pub fn execute_func(&mut self, key: &str) -> bool {
let item = match self.functions.get(key) {
Some(v) => v.clone(),
None => return false,
};
match item {
FunctionItem::Builtin(f) => f(self),
FunctionItem::TokenString(ts) => self.execute_token_string(&ts),
}
}
pub fn execute_token_string(&mut self, ts: &TokenString) -> bool {
for token in &ts.tokens {
if let Token::Identifier(id) = &token {
if !id.is_literal {
if !self.execute_func(&id.name) {
return false;
}
continue;
}
}
if !self.push_token(&token) {
return false;
}
}
true
}
pub fn execute(&mut self, token: &Token) -> bool {
match token {
Token::Identifier(id) if !id.is_literal => {
self.execute_func(&id.name)
}
_ => self.push_token(token),
}
}
pub fn stack_top(&self) -> Option<&StackValue> {
self.stack.last()
}
}