use rasterize::*;
use std::{
cell::{self, RefCell},
cmp::{Ordering, PartialEq},
collections::HashMap,
fmt,
io::Read,
num::ParseFloatError,
rc::Rc,
str::FromStr,
string::FromUtf8Error,
};
#[derive(Clone)]
struct PSGraphicState {
color: LinColor,
miter_limit: Scalar,
stroke_style: StrokeStyle,
transform: Transform,
transform_inverse: Option<Transform>,
path: PathBuilder,
clip_path: Path,
}
impl PSGraphicState {
fn new(transform: Transform) -> Self {
Self {
color: LinColor::new(0.0, 0.0, 0.0, 1.0),
miter_limit: 10.0,
stroke_style: StrokeStyle {
width: 1.0,
line_join: LineJoin::Miter(10.0),
line_cap: LineCap::Butt,
},
transform,
transform_inverse: None,
path: PathBuilder::new(),
clip_path: Path::empty(),
}
}
fn transform_set(&mut self, tr: Transform) {
self.transform = tr;
self.transform_inverse = None;
}
fn transform_push(&mut self, tr: Transform) {
self.transform = self.transform * tr;
self.transform_inverse = None;
}
fn transform_get(&self) -> Transform {
self.transform
}
fn transform_inverse_get(&mut self) -> Result<Transform, PSError> {
if let Some(tr) = self.transform_inverse {
return Ok(tr);
}
match self.transform.invert() {
None => Err(PSError::NotInvertable),
Some(tr) => {
self.transform_inverse = Some(tr);
Ok(tr)
}
}
}
}
struct PSState {
rasterizer: Box<dyn Rasterizer>,
image: ImageOwned<LinColor>,
transform_default: Transform,
stack: Vec<PSValue>,
dict_stack: Vec<PSDict>,
graphic_stack: Vec<PSGraphicState>,
}
impl PSState {
fn new() -> Self {
Self {
rasterizer: Box::new(ActiveEdgeRasterizer::default()),
image: ImageOwned::new_default(Size {
width: 0,
height: 0,
}),
transform_default: Transform::identity(),
stack: Vec::new(),
dict_stack: vec![create_global_dict(), PSDict::new()],
graphic_stack: vec![],
}
}
fn pop(&mut self) -> Result<PSValue, PSError> {
self.stack.pop().ok_or(PSError::StackUnderflow)
}
fn pop_point(&mut self) -> Result<Point, PSError> {
let y = self.pop()?.try_into_number()?;
let x = self.pop()?.try_into_number()?;
Ok(Point::new(x, y))
}
fn push(&mut self, value: impl Into<PSValue>) {
self.stack.push(value.into())
}
fn load(&mut self, key: &PSSymbol) -> Result<PSValue, PSError> {
for dict in self.dict_stack.iter().rev() {
if let Some(val) = dict.get(key) {
return Ok(val);
}
}
Err(PSError::NotDefined(key.clone()))
}
fn store(&mut self, key: PSSymbol, val: impl Into<PSValue>) {
if let Some(dict) = self.dict_stack.last_mut() {
dict.insert(key, val.into());
}
}
fn graphic(&mut self) -> &mut PSGraphicState {
if self.graphic_stack.is_empty() {
self.graphic_stack
.push(PSGraphicState::new(self.transform_default));
}
let last_index = self.graphic_stack.len() - 1;
&mut self.graphic_stack[last_index]
}
fn graphic_save(&mut self) {
let state = self.graphic().clone();
self.graphic_stack.push(state);
}
fn graphic_restore(&mut self) {
self.graphic_stack.pop();
}
fn eval(&mut self, val: PSValue) -> Result<(), PSError> {
use PSValue::*;
match val {
Symbol(symbol) => {
let value = self.load(&symbol)?;
let not_proc = value.try_run_opt(self)?;
self.stack.extend(not_proc);
}
Comment(comment) => {
if let Some(bbox_str) = comment.strip_prefix("%BoundingBox:") {
let mut bbox_iter = bbox_str.split_whitespace();
if let Some(bbox) = (|| {
let x = bbox_iter.next()?.parse().ok()?;
let y = bbox_iter.next()?.parse().ok()?;
let width: Scalar = bbox_iter.next()?.parse().ok()?;
let height: Scalar = bbox_iter.next()?.parse().ok()?;
Some(BBox::new((x, y), (x + width, y + height)))
})() {
self.image = ImageOwned::new_default(Size {
width: bbox.width() as usize,
height: bbox.height() as usize,
});
self.transform_default = Transform::new_scale(1.0, -1.0)
.pre_translate(-bbox.x(), -bbox.y() - bbox.height());
}
}
}
Fn(fun) => fun.run(self)?,
_ => self.stack.push(val),
}
Ok(())
}
}
fn create_global_dict() -> PSDict {
fn bind_fn(
dict: &mut HashMap<PSSymbol, PSValue>,
name: &'static str,
def: impl Fn(&mut PSState) -> Result<(), PSError> + 'static,
) {
let fun = PSFnBuildIn::new(name, def);
dict.insert(PSSymbol(name.to_string()), PSValue::Fn(Rc::new(fun)));
}
let mut global_dict: HashMap<PSSymbol, PSValue> = HashMap::new();
let dict = &mut global_dict;
bind_fn(dict, "copy", |state| match state.pop()? {
PSValue::Number(count) => {
let count = count as usize;
let range = state.stack.len() - count..state.stack.len();
for index in range {
let val = state.stack[index].clone();
state.push(val);
}
Ok(())
}
PSValue::Dict(dst) => {
let src = state.pop()?.try_into_dict()?;
for (key, value) in src.borrow().iter() {
dst.insert(key.clone(), value.clone());
}
Ok(())
}
val => Err(PSError::InvalidValue(val)),
});
bind_fn(dict, "length", |state| match state.pop()? {
PSValue::Array(array) => {
state.push(array.len());
Ok(())
}
PSValue::Dict(dict) => {
state.push(dict.len());
Ok(())
}
PSValue::String(string) => {
state.push(string.len());
Ok(())
}
val => Err(PSError::InvalidValue(val)),
});
bind_fn(dict, "pop", |state| {
state.pop()?;
Ok(())
});
bind_fn(dict, "clear", |state| {
state.stack.clear();
Ok(())
});
bind_fn(dict, "exch", |state| {
let a = state.pop()?;
let b = state.pop()?;
state.push(a);
state.push(b);
Ok(())
});
bind_fn(dict, "dup", |state| {
let value = state.stack.last().ok_or(PSError::StackUnderflow)?.clone();
state.stack.push(value);
Ok(())
});
bind_fn(dict, "index", |state| {
let index = state.pop()?.try_into_number()? as usize;
let value = state
.stack
.get(state.stack.len() - index - 1)
.ok_or_else(|| PSError::StackUnderflow)?
.clone();
state.stack.push(value);
Ok(())
});
bind_fn(dict, "roll", |state| {
let roll = state.pop()?.try_into_number()?;
let size = state.pop()?.try_into_number()? as usize;
let stack_len = state.stack.len();
if stack_len < size {
return Err(PSError::StackUnderflow);
}
let slice = &mut state.stack[stack_len - size..];
if roll > 0.0 {
let roll = roll as usize % size;
slice.rotate_right(roll);
} else {
let roll = -roll as usize % size;
slice.rotate_left(roll);
}
Ok(())
});
bind_fn(dict, "gsave", |state| {
state.graphic_save();
Ok(())
});
bind_fn(dict, "grestore", |state| {
state.graphic_restore();
Ok(())
});
bind_fn(dict, "newpath", |state| {
state.graphic().path = Path::builder();
Ok(())
});
bind_fn(dict, "clippath", |state| {
state.graphic().clip_path = state.graphic().path.build();
Ok(())
});
bind_fn(dict, "moveto", |state| {
let point = state.pop_point()?;
state.graphic().path.move_to(point);
Ok(())
});
bind_fn(dict, "lineto", |state| {
let point = state.pop_point()?;
state.graphic().path.line_to(point);
Ok(())
});
bind_fn(dict, "rlineto", |state| {
let current = state.graphic().path.position();
let point = state.pop_point()?;
state.graphic().path.line_to(current + point);
Ok(())
});
bind_fn(dict, "curveto", |state| {
let p3 = state.pop_point()?;
let p2 = state.pop_point()?;
let p1 = state.pop_point()?;
state.graphic().path.cubic_to(p1, p2, p3);
Ok(())
});
bind_fn(dict, "closepath", |state| {
state.graphic().path.close();
Ok(())
});
bind_fn(dict, "currentpoint", |state| {
let point = state.graphic().path.position();
state.push(point.x());
state.push(point.y());
Ok(())
});
bind_fn(dict, "fill", |state| {
let gstate = state.graphic();
let transform = gstate.transform_get();
let color = gstate.color;
let path = gstate.path.build();
path.fill(
&state.rasterizer,
transform,
FillRule::NonZero,
color,
state.image.as_mut(),
);
Ok(())
});
bind_fn(dict, "stroke", |state| {
let gstate = state.graphic();
let transform = gstate.transform_get();
let color = gstate.color;
let path = gstate.path.build().stroke(gstate.stroke_style);
path.fill(
&state.rasterizer,
transform,
FillRule::NonZero,
color,
state.image.as_mut(),
);
Ok(())
});
bind_fn(dict, "setrgbcolor", |state| {
let b = srgb_to_linear(state.pop()?.try_into_number()? as f32);
let g = srgb_to_linear(state.pop()?.try_into_number()? as f32);
let r = srgb_to_linear(state.pop()?.try_into_number()? as f32);
state.graphic().color = LinColor::new(r, g, b, 1.0);
Ok(())
});
bind_fn(dict, "setgray", |state| {
let v = state.pop()?.try_into_number()? as f32;
state.graphic().color = LinColor::new(v, v, v, 1.0);
Ok(())
});
bind_fn(dict, "currentflat", |state| {
state.push(1.0);
Ok(())
});
bind_fn(dict, "setflat", |state| {
let _flatness = state.pop()?.try_into_number()?;
Ok(())
});
bind_fn(dict, "setlinejoin", |state| {
let id = state.pop()?.try_into_number()? as usize;
let line_join = match id {
0 => LineJoin::Miter(state.graphic().miter_limit),
1 => LineJoin::Round,
2 => LineJoin::Bevel,
_ => return Err(PSError::InvalidValue((id as Scalar).into())),
};
state.graphic().stroke_style.line_join = line_join;
Ok(())
});
bind_fn(dict, "setlinecap", |state| {
let id = state.pop()?.try_into_number()? as usize;
let line_cap = match id {
0 => LineCap::Butt,
1 => LineCap::Round,
2 => LineCap::Square,
_ => return Err(PSError::InvalidValue((id as Scalar).into())),
};
state.graphic().stroke_style.line_cap = line_cap;
Ok(())
});
bind_fn(dict, "setmiterlimit", |state| {
let miter_limit = state.pop()?.try_into_number()?;
state.graphic().miter_limit = miter_limit;
Ok(())
});
bind_fn(dict, "setlinewidth", |state| {
let width = state.pop()?.try_into_number()?;
state.graphic().stroke_style.width = width;
Ok(())
});
let try_pop_matrix = Rc::new(
|state: &mut PSState| -> Result<Option<Transform>, PSError> {
match state.pop()? {
PSValue::Matrix(transform) => Ok(Some(transform)),
value => {
state.push(value);
Ok(None)
}
}
},
);
bind_fn(dict, "matrix", |state| {
state.push(Transform::identity());
Ok(())
});
bind_fn(dict, "currentmatrix", |state| {
let _ = state.pop()?.try_into_matrix()?;
let ctm = state.graphic().transform_get();
state.push(ctm);
Ok(())
});
bind_fn(dict, "setmatrix", |state| {
let ctm = state.pop()?.try_into_matrix()?;
state.graphic().transform_set(ctm);
Ok(())
});
bind_fn(dict, "concat", |state| {
let tr = state.pop()?.try_into_matrix()?;
state.graphic().transform_push(tr);
Ok(())
});
bind_fn(dict, "concatmatrix", |state| {
let _m = state.pop()?.try_into_matrix()?;
let r = state.pop()?.try_into_matrix()?;
let l = state.pop()?.try_into_matrix()?;
state.push(l * r);
Ok(())
});
bind_fn(dict, "invertmatrix", |state| {
let _dst = state.pop()?.try_into_matrix()?;
let src = state.pop()?.try_into_matrix()?;
state.push(src.invert().ok_or(PSError::NotInvertable)?);
Ok(())
});
bind_fn(dict, "transform", {
let try_pop_matrix = try_pop_matrix.clone();
move |state| {
let tr = try_pop_matrix(state)?.unwrap_or(state.graphic().transform_get());
let point = state.pop_point()?;
let result = tr.apply(point);
state.push(result.x());
state.push(result.y());
Ok(())
}
});
bind_fn(dict, "itransform", {
let try_pop_matrix = try_pop_matrix.clone();
move |state| {
let tr = match try_pop_matrix(state)? {
Some(tr) => tr.invert().ok_or(PSError::NotInvertable)?,
None => state.graphic().transform_inverse_get()?,
};
let point = state.pop_point()?;
let result = tr.apply(point);
state.push(result.x());
state.push(result.y());
Ok(())
}
});
bind_fn(dict, "translate", {
let try_pop_matrix = try_pop_matrix.clone();
move |state| {
let matrix = try_pop_matrix(state)?;
let point = state.pop_point()?;
let translate = Transform::new_translate(point.x(), point.y());
match matrix {
Some(matrix) => state.push(translate * matrix),
None => state.graphic().transform_push(translate),
}
Ok(())
}
});
bind_fn(dict, "scale", {
let try_pop_matrix = try_pop_matrix.clone();
move |state| {
let matrix = try_pop_matrix(state)?;
let point = state.pop_point()?;
let scale = Transform::new_scale(point.x(), point.y());
match matrix {
Some(matrix) => state.push(scale * matrix),
None => state.graphic().transform_push(scale),
}
Ok(())
}
});
bind_fn(dict, "rotate", {
let try_pop_matrix = try_pop_matrix.clone();
move |state| {
let matrix = try_pop_matrix(state)?;
let angle = state.pop()?.try_into_number()?;
let rotate = Transform::new_rotate(angle);
match matrix {
Some(matrix) => state.push(rotate * matrix),
None => state.graphic().transform_push(rotate),
}
Ok(())
}
});
bind_fn(dict, "def", |state| {
let value = match state.pop()? {
PSValue::Block(block) => PSValue::Fn(Rc::new(PSProc(block))),
value => value,
};
let name = state.pop()?.try_into_symbol()?;
state.store(name, value);
Ok(())
});
bind_fn(dict, "begin", |state| {
let dict = state.pop()?.try_into_dict()?;
state.dict_stack.push(dict);
Ok(())
});
bind_fn(dict, "end", |state| {
let _ = state.dict_stack.pop();
Ok(())
});
bind_fn(dict, "bind", |state| {
let block = state.pop()?.try_into_block()?;
let resolved = block
.into_iter()
.map(|val| match val {
PSValue::Symbol(ref sym) => match state.load(sym) {
Ok(op @ PSValue::Fn(_)) => op,
_ => val,
},
_ => val,
})
.collect();
state.push(PSValue::Block(resolved));
Ok(())
});
bind_fn(dict, "dict", |state| {
let _size = state.pop()?;
state.push(PSValue::Dict(PSDict::new()));
Ok(())
});
bind_fn(dict, "load", |state| {
let key = state.pop()?.try_into_symbol()?;
let val = state.load(&key)?;
state.push(val);
Ok(())
});
bind_fn(dict, "get", |state| {
let key = state.pop()?.try_into_symbol()?;
let dict = state.pop()?.try_into_dict()?;
let val = dict.get(&key).ok_or_else(|| PSError::NotDefined(key))?;
state.push(val);
Ok(())
});
bind_fn(dict, "where", |state| {
let key = state.pop()?.try_into_symbol()?;
for dict in state.dict_stack.iter().rev() {
if dict.contains_key(&key) {
let dict = dict.clone();
state.push(dict);
state.push(true);
return Ok(());
}
}
state.push(false);
Ok(())
});
dict.insert(PSSymbol::new("true".to_string()), PSValue::Bool(true));
dict.insert(PSSymbol::new("false".to_string()), PSValue::Bool(false));
bind_fn(dict, "eq", |state| {
let a = state.pop()?;
let b = state.pop()?;
state.push(a == b);
Ok(())
});
bind_fn(dict, "ne", |state| {
let a = state.pop()?;
let b = state.pop()?;
state.push(a != b);
Ok(())
});
let cmp = Rc::new(|state: &mut PSState| {
let a = state.pop()?;
let b = state.pop()?;
use PSValue::*;
match (a, b) {
(String(a), String(b)) => Ok(b.cmp(&a)),
(Number(a), Number(b)) => b
.partial_cmp(&a)
.ok_or_else(move || PSError::NotComparable(b.into(), a.into())),
(a, b) => Err(PSError::NotComparable(b, a)),
}
});
bind_fn(dict, "ge", {
let cmp = cmp.clone();
move |state| {
let ord = cmp(state)?;
state.push(ord == Ordering::Equal || ord == Ordering::Greater);
Ok(())
}
});
bind_fn(dict, "gt", {
let cmp = cmp.clone();
move |state| {
let ord = cmp(state)?;
state.push(ord == Ordering::Greater);
Ok(())
}
});
bind_fn(dict, "le", {
let cmp = cmp.clone();
move |state| {
let ord = cmp(state)?;
state.push(ord == Ordering::Equal || ord == Ordering::Less);
Ok(())
}
});
bind_fn(dict, "lt", {
let cmp = cmp.clone();
move |state| {
let ord = cmp(state)?;
state.push(ord == Ordering::Less);
Ok(())
}
});
bind_fn(dict, "if", |state| {
let succ = state.pop()?;
let cond = state.pop()?.try_into_bool()?;
if cond {
succ.try_run(state)?;
}
Ok(())
});
bind_fn(dict, "ifelse", |state| {
let fail = state.pop()?;
let succ = state.pop()?;
let cond = state.pop()?.try_into_bool()?;
if cond {
succ.try_run(state)?;
} else {
fail.try_run(state)?;
}
Ok(())
});
bind_fn(dict, "for", |state| {
let proc = state.pop()?;
let limit = state.pop()?.try_into_number()?;
let inc = state.pop()?.try_into_number()?;
let mut val = state.pop()?.try_into_number()?;
while val < limit {
proc.clone().try_run(state)?;
val += inc;
}
Ok(())
});
bind_fn(dict, "stop", |_state| Err(PSError::Stopped));
bind_fn(dict, "stopped", |state| {
let scope = state.pop()?;
match scope.try_run(state) {
Err(PSError::Stopped) => {
state.push(true);
Ok(())
}
val => {
let val = val?;
state.push(false);
Ok(val)
}
}
});
bind_fn(dict, "add", |state| {
let a = state.pop()?.try_into_number()?;
let b = state.pop()?.try_into_number()?;
state.push(a + b);
Ok(())
});
bind_fn(dict, "mul", |state| {
let a = state.pop()?.try_into_number()?;
let b = state.pop()?.try_into_number()?;
state.push(a * b);
Ok(())
});
bind_fn(dict, "sqrt", |state| {
let a = state.pop()?.try_into_number()?;
state.push(a.sqrt());
Ok(())
});
bind_fn(dict, "div", |state| {
let a = state.pop()?.try_into_number()?;
let b = state.pop()?.try_into_number()?;
state.push(b / a);
Ok(())
});
bind_fn(dict, "sub", |state| {
let a = state.pop()?.try_into_number()?;
let b = state.pop()?.try_into_number()?;
state.push(b - a);
Ok(())
});
bind_fn(dict, "neg", |state| {
let val = state.pop()?.try_into_number()?;
state.push(-val);
Ok(())
});
bind_fn(dict, "round", |state| {
let val = state.pop()?.try_into_number()?;
state.push(val.round());
Ok(())
});
bind_fn(dict, "sin", |state| {
let a = state.pop()?.try_into_number()?;
state.push((a / (2.0 * PI)).sin());
Ok(())
});
bind_fn(dict, "cos", |state| {
let a = state.pop()?.try_into_number()?;
state.push((a / (2.0 * PI)).cos());
Ok(())
});
bind_fn(dict, "atan", |state| {
let den = state.pop()?.try_into_number()?;
let num = state.pop()?.try_into_number()?;
state.push(num.atan2(den) * 2.0 * PI);
Ok(())
});
bind_fn(dict, "pstack", |state| {
eprintln!("STACK:");
for val in state.stack.iter().rev() {
eprintln!(" {:?}", val);
}
Ok(())
});
bind_fn(dict, "save", |state| {
eprintln!("[not supported] save");
state.push(PSValue::Comment("Dummy VM snapshot".to_string()));
Ok(())
});
bind_fn(dict, "restore", |state| {
eprintln!("[not supported] restore");
state.pop()?;
Ok(())
});
bind_fn(dict, "setdash", |state| {
eprintln!("[not supported] setdash");
let _offset = state.pop()?.try_into_number()?;
let _array = state.pop()?.try_into_array()?;
Ok(())
});
bind_fn(dict, "showpage", |_state| Ok(()));
bind_fn(dict, "ashow", |state| {
let _a = state.pop_point()?;
let _text = state.pop()?.try_into_string()?;
Ok(())
});
PSDict(Rc::new(RefCell::new(global_dict)))
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct PSSymbol(String);
impl PSSymbol {
fn new(string: String) -> Self {
Self(string)
}
fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, PartialEq)]
struct PSDict(Rc<RefCell<HashMap<PSSymbol, PSValue>>>);
impl PSDict {
fn new() -> Self {
Self(Rc::new(RefCell::new(HashMap::new())))
}
fn len(&self) -> usize {
self.borrow().len()
}
fn get(&self, key: &PSSymbol) -> Option<PSValue> {
self.borrow().get(key).cloned()
}
fn contains_key(&self, key: &PSSymbol) -> bool {
self.borrow().contains_key(key)
}
fn insert(&self, key: PSSymbol, val: impl Into<PSValue>) -> Option<PSValue> {
self.borrow_mut().insert(key, val.into())
}
fn borrow(&self) -> cell::Ref<'_, HashMap<PSSymbol, PSValue>> {
self.0.borrow()
}
fn borrow_mut(&self) -> cell::RefMut<'_, HashMap<PSSymbol, PSValue>> {
self.0.borrow_mut()
}
}
impl fmt::Debug for PSDict {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.borrow().fmt(f)
}
}
trait PSFn: fmt::Debug {
fn run(&self, state: &mut PSState) -> Result<(), PSError>;
}
struct PSFnBuildIn<F> {
name: &'static str,
fun: F,
}
impl<F> PSFnBuildIn<F> {
fn new(name: &'static str, fun: F) -> Self {
Self { name, fun }
}
}
impl<F> PSFn for PSFnBuildIn<F>
where
F: Fn(&mut PSState) -> Result<(), PSError>,
{
fn run(&self, state: &mut PSState) -> Result<(), PSError> {
(self.fun)(state)
}
}
impl<F> fmt::Debug for PSFnBuildIn<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.name.fmt(f)
}
}
struct PSProc(Vec<PSValue>);
impl PSFn for PSProc {
fn run(&self, state: &mut PSState) -> Result<(), PSError> {
for val in self.0.iter() {
state.eval(val.clone())?;
}
Ok(())
}
}
impl fmt::Debug for PSProc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.iter()).finish()
}
}
#[derive(Clone)]
enum PSValue {
Bool(bool),
Number(Scalar),
Symbol(PSSymbol),
Quote(PSSymbol),
String(String),
Comment(String),
Block(Vec<PSValue>),
Array(Vec<PSValue>),
Matrix(Transform),
Dict(PSDict),
Fn(Rc<dyn PSFn>),
}
impl PSValue {
fn try_into_symbol(self) -> Result<PSSymbol, PSError> {
match self {
PSValue::Quote(symbol) => Ok(symbol),
_ => Err(PSError::ExpectedQuote),
}
}
fn try_into_number(self) -> Result<Scalar, PSError> {
match self {
PSValue::Number(value) => Ok(value),
_ => Err(PSError::ExpectedNumber),
}
}
fn try_into_dict(self) -> Result<PSDict, PSError> {
match self {
PSValue::Dict(dict) => Ok(dict),
_ => Err(PSError::ExpectedDict),
}
}
fn try_into_array(self) -> Result<Vec<PSValue>, PSError> {
match self {
PSValue::Array(array) => Ok(array),
_ => Err(PSError::ExpectedArray),
}
}
fn try_into_matrix(self) -> Result<Transform, PSError> {
match self {
PSValue::Matrix(tr) => Ok(tr),
_ => Err(PSError::ExpectedMatrix),
}
}
fn try_into_block(self) -> Result<Vec<PSValue>, PSError> {
match self {
PSValue::Block(block) => Ok(block),
_ => Err(PSError::ExpectedBlock),
}
}
fn try_into_bool(self) -> Result<bool, PSError> {
match self {
PSValue::Bool(val) => Ok(val),
_ => Err(PSError::ExpectedBool),
}
}
fn try_into_string(self) -> Result<String, PSError> {
match self {
PSValue::String(string) => Ok(string),
_ => Err(PSError::ExpectedBool),
}
}
fn try_run_opt(self, state: &mut PSState) -> Result<Option<PSValue>, PSError> {
match self {
PSValue::Fn(fun) => fun.run(state)?,
PSValue::Block(block) => {
for val in block {
state.eval(val)?;
}
}
val => return Ok(Some(val)),
}
Ok(None)
}
fn try_run(self, state: &mut PSState) -> Result<(), PSError> {
match self.try_run_opt(state)? {
None => Ok(()),
Some(_) => Err(PSError::ExpectedProc),
}
}
}
impl PartialEq<PSValue> for PSValue {
fn eq(&self, other: &PSValue) -> bool {
use PSValue::*;
match (self, other) {
(Bool(a), Bool(b)) => a.eq(b),
(Number(a), Number(b)) => a.eq(b),
(Symbol(a), Symbol(b)) => a.eq(b),
(Quote(a), Quote(b)) => a.eq(b),
(String(a), String(b)) => a.eq(b),
(Comment(a), Comment(b)) => a.eq(b),
(Block(a), Block(b)) => a.eq(b),
(Array(a), Array(b)) => a.eq(b),
(Dict(a), Dict(b)) => a.eq(b),
_ => false,
}
}
}
impl From<Scalar> for PSValue {
fn from(value: Scalar) -> Self {
PSValue::Number(value)
}
}
impl From<usize> for PSValue {
fn from(value: usize) -> Self {
PSValue::Number(value as Scalar)
}
}
impl From<bool> for PSValue {
fn from(value: bool) -> Self {
PSValue::Bool(value)
}
}
impl From<PSDict> for PSValue {
fn from(dict: PSDict) -> Self {
PSValue::Dict(dict)
}
}
impl From<Transform> for PSValue {
fn from(tr: Transform) -> Self {
PSValue::Matrix(tr)
}
}
impl fmt::Debug for PSValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use PSValue::*;
match self {
Bool(val) => f.debug_tuple("Bool").field(val).finish(),
Number(num) => f.debug_tuple("Number").field(num).finish(),
Symbol(sym) => f.debug_tuple("Symbol").field(&sym.as_str()).finish(),
Quote(sym) => f.debug_tuple("Quote").field(&sym.as_str()).finish(),
String(string) => f.debug_tuple("String").field(string).finish(),
Comment(string) => f.debug_tuple("Comment").field(string).finish(),
Block(block) => f.debug_tuple("Block").field(&block).finish(),
Array(array) => f.debug_tuple("Array").field(&array).finish(),
Dict(dict) => f.debug_tuple("Dict").field(&dict).finish(),
Matrix(tr) => f.debug_tuple("Matrix").field(&tr).finish(),
Fn(fun) => f.debug_tuple("Fn").field(&fun).finish(),
}
}
}
struct PSParser<I> {
input: I,
buf: Vec<u8>,
}
impl<I: Read> PSParser<I> {
fn new(input: I) -> Self {
Self {
input,
buf: Default::default(),
}
}
fn parse(&mut self) -> Result<PSValue, PSError> {
let byte = loop {
let byte = self.read_byte()?;
if !matches!(byte, b' ' | b'\n' | b'\r' | b'\t' | b'\x00' | b'\x0c') {
break byte;
}
};
match byte {
b'/' => {
let symbol = PSSymbol::new(self.read_symbol()?);
Ok(PSValue::Quote(symbol))
}
b'%' => Ok(PSValue::Comment(self.read_while(|b| b != b'\n')?)),
b'-' | b'+' | b'0'..=b'9' | b'.' => {
self.push_byte(byte);
let number = self.read_number()?;
Ok(PSValue::Number(number))
}
b'_' | b'a'..=b'z' | b'A'..=b'Z' => {
self.push_byte(byte);
let symbol = PSSymbol::new(self.read_symbol()?);
Ok(PSValue::Symbol(symbol))
}
b'(' => {
let string = self.read_while(|byte| byte != b')')?;
self.read_byte()?;
Ok(PSValue::String(string))
}
b'{' => {
let mut block = Vec::new();
loop {
match self.parse() {
Ok(cmd) => block.push(cmd),
Err(PSError::UnclosedBlock) => break,
Err(error) => return Err(error),
}
}
Ok(PSValue::Block(block))
}
b'}' => Err(PSError::UnclosedBlock),
b'[' => {
let mut array = Vec::new();
loop {
match self.parse() {
Ok(cmd) => array.push(cmd),
Err(PSError::UnclosedArray) => break,
Err(error) => return Err(error),
}
}
Ok(PSValue::Array(array))
}
b']' => Err(PSError::UnclosedArray),
_ => Err(PSError::InputUnexpected(byte)),
}
}
fn read_byte(&mut self) -> Result<u8, PSError> {
match self.buf.pop() {
None => {
let mut byte = [0; 1];
if let Err(error) = self.input.read_exact(&mut byte[..]) {
if error.kind() == std::io::ErrorKind::UnexpectedEof {
return Err(PSError::InputEmpty);
}
return Err(error.into());
}
Ok(byte[0])
}
Some(byte) => Ok(byte),
}
}
fn push_byte(&mut self, byte: u8) {
self.buf.push(byte)
}
fn read_while(&mut self, mut pred: impl FnMut(u8) -> bool) -> Result<String, PSError> {
let mut result = Vec::new();
loop {
match self.read_byte() {
Ok(byte) => {
if pred(byte) {
result.push(byte);
} else {
self.push_byte(byte);
break;
}
}
Err(PSError::InputEmpty) => break,
Err(error) => return Err(error),
}
}
Ok(String::from_utf8(result)?)
}
fn read_number(&mut self) -> Result<Scalar, PSError> {
let number =
self.read_while(|byte| matches!(byte, b'0'..=b'9' | b'.' | b'+' | b'-' | b'e' | b'E'))?;
Ok(Scalar::from_str(&number)?)
}
fn read_symbol(&mut self) -> Result<String, PSError> {
let symbol = self.read_while(|byte| {
!matches!(
byte,
b' ' | b'\n' | b'\r' | b'\t' | b'\x00' | b'\x0c' | b'[' | b']' | b'{' | b'}' | b'/'
)
})?;
Ok(symbol)
}
}
impl<I: Read> Iterator for PSParser<I> {
type Item = Result<PSValue, PSError>;
fn next(&mut self) -> Option<Self::Item> {
match self.parse() {
Err(PSError::InputEmpty) => None,
item => Some(item),
}
}
}
#[derive(Debug)]
enum PSError {
ExpectedArray,
ExpectedBlock,
ExpectedBool,
ExpectedDict,
ExpectedMatrix,
ExpectedNumber,
ExpectedProc,
ExpectedQuote,
Float(ParseFloatError),
IOError(std::io::Error),
InputEmpty,
InputUnexpected(u8),
InvalidValue(PSValue),
NotComparable(PSValue, PSValue),
NotDefined(PSSymbol),
NotInvertable,
StackUnderflow,
Stopped,
UnclosedArray,
UnclosedBlock,
Utf8(FromUtf8Error),
}
impl From<std::io::Error> for PSError {
fn from(error: std::io::Error) -> Self {
Self::IOError(error)
}
}
impl From<FromUtf8Error> for PSError {
fn from(error: FromUtf8Error) -> Self {
Self::Utf8(error)
}
}
impl From<ParseFloatError> for PSError {
fn from(error: ParseFloatError) -> Self {
Self::Float(error)
}
}
fn main() -> Result<(), PSError> {
use std::{
fs::File,
io::{BufReader, BufWriter},
};
let file = BufReader::new(File::open("/mnt/data/downloads/escher.ps")?);
let parser = PSParser::new(file);
let mut state = PSState::new();
for val in parser {
let val = val?;
println!("{:?}", val);
if let Err(err) = state.eval(val) {
if let PSError::InputEmpty = err {
break;
}
eprintln!("ERROR: {:?}", err);
for val in PSParser::new(std::io::stdin()) {
if let Err(err) = state.eval(val?) {
eprintln!("ERROR: {:?}", err);
}
}
return Ok(());
}
}
let mut image = BufWriter::new(File::create("/tmp/eps.bmp")?);
state.image.write_bmp(&mut image)?;
Ok(())
}