use crate::result::{RoarError, RoarResult};
#[derive(Debug, PartialEq, PartialOrd, Clone, Copy)]
#[repr(u8)]
pub enum Op {
Load = 0x6c,
LoadConst = 0x63,
Set = 0x73,
Get = 0x67,
Swap = 0x77,
Perlin = 0x70,
Fbm = 0x66,
RidgedMulti = 0x72,
Value = 0x76,
Add = 0x2b,
Sub = 0x2d,
Mul = 0x2a,
Div = 0x2f,
Min = 0x6e,
Max = 0x78,
Pwr = 0x5e,
Neg = 0x21,
RightShift = 0x3e,
LeftShift = 0x3c,
GetCtx1 = 0x31,
GetCtx2 = 0x32,
SetCtx4 = 0x34,
SetCtx5 = 0x35,
PutOnCurve = 0x75,
}
pub mod ops {
use super::Op;
pub const LOAD: u8 = Op::Load as u8;
pub const LOAD_CONST: u8 = Op::LoadConst as u8;
pub const SET: u8 = Op::Set as u8;
pub const GET: u8 = Op::Get as u8;
pub const SWAP: u8 = Op::Swap as u8;
pub const PERLIN: u8 = Op::Perlin as u8;
pub const FBM: u8 = Op::Fbm as u8;
pub const RIDGED_MULTI: u8 = Op::RidgedMulti as u8;
pub const VALUE: u8 = Op::Value as u8;
pub const ADD: u8 = Op::Add as u8;
pub const SUB: u8 = Op::Sub as u8;
pub const MUL: u8 = Op::Mul as u8;
pub const DIV: u8 = Op::Div as u8;
pub const MIN: u8 = Op::Min as u8;
pub const MAX: u8 = Op::Max as u8;
pub const PWR: u8 = Op::Pwr as u8;
pub const NEG: u8 = Op::Neg as u8;
pub const RIGHT_SHIFT: u8 = Op::RightShift as u8;
pub const LEFT_SHIFT: u8 = Op::LeftShift as u8;
pub const GET_CTX1: u8 = Op::GetCtx1 as u8;
pub const GET_CTX2: u8 = Op::GetCtx2 as u8;
pub const SET_CTX4: u8 = Op::SetCtx4 as u8;
pub const SET_CTX5: u8 = Op::SetCtx5 as u8;
pub const PUT_ON_CURVE: u8 = Op::PutOnCurve as u8;
}
pub fn parse_bytecode(bytecode: &[u8]) -> RoarResult<Vec<Op>> {
use ops::*;
let mut ops = vec![];
for char in bytecode {
let op = match *char {
LOAD => Op::Load,
LOAD_CONST => Op::LoadConst,
SET => Op::Set,
GET => Op::Get,
SWAP => Op::Swap,
PERLIN => Op::Perlin,
FBM => Op::Fbm,
RIDGED_MULTI => Op::RidgedMulti,
VALUE => Op::Value,
ADD => Op::Add,
SUB => Op::Sub,
MUL => Op::Mul,
DIV => Op::Div,
MIN => Op::Min,
MAX => Op::Max,
PWR => Op::Pwr,
NEG => Op::Neg,
RIGHT_SHIFT => Op::RightShift,
LEFT_SHIFT => Op::LeftShift,
GET_CTX1 => Op::GetCtx1,
GET_CTX2 => Op::GetCtx2,
SET_CTX4 => Op::SetCtx4,
SET_CTX5 => Op::SetCtx5,
PUT_ON_CURVE => Op::PutOnCurve,
0x20 | 0x0a | 0x09 => continue,
_ => return Err(RoarError::ParsingUnexpectedCode),
};
ops.push(op);
}
Ok(ops)
}
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub enum BytecodeValue {
F64(f64),
I64(i64),
}
impl BytecodeValue {
pub fn as_f64(&self) -> Option<f64> {
match self {
BytecodeValue::F64(val) => Some(*val),
BytecodeValue::I64(_) => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
BytecodeValue::I64(val) => Some(*val),
BytecodeValue::F64(_) => None,
}
}
}
pub fn parse_input_section(input: &[char]) -> RoarResult<Vec<BytecodeValue>> {
let mut values = vec![];
let mut i = 0;
loop {
if i >= input.len() {
break;
}
let c = input[i];
i += 1;
let v = match c {
'i' => {
let mut read_buf = 0i64;
if i >= input.len() {
return Err(RoarError::ParsingInUnexpectedEof);
}
let sign = if input[i] == '-' {
i += 1;
-1
} else {
1
};
loop {
if i >= input.len() {
break;
}
let c = input[i];
if c.is_digit(10) {
i += 1;
read_buf *= 10;
read_buf += (c as i64) - 48;
} else {
break;
}
}
BytecodeValue::I64(read_buf * sign)
}
'f' => {
let mut read_buf = 0f64;
if i >= input.len() {
return Err(RoarError::ParsingInUnexpectedEof);
}
let sign = if input[i] == '-' {
i += 1;
-1.0
} else {
1.0
};
let mut dec = 0i32;
loop {
if i >= input.len() {
break;
}
let c = input[i];
if c.is_digit(10) {
i += 1;
read_buf *= 10.0;
read_buf += ((c as u8) - 48) as f64;
if dec > 0 {
dec += 1;
}
} else if c == '.' {
i += 1;
if dec > 0 {
return Err(RoarError::ParsingInUnexpectedChar);
}
dec += 1;
} else {
break;
}
}
BytecodeValue::F64(read_buf as f64 / (10f64).powi(dec - 1) * sign)
}
'\n' | ' ' | '\t' => continue,
_ => return Err(RoarError::ParsingInUnexpectedChar),
};
values.push(v);
}
Ok(values)
}