mirror of
https://github.com/SpaceManiac/SpacemanDMM.git
synced 2025-12-23 05:36:47 +00:00
Apply a variety of rustfmt suggestions
This commit is contained in:
parent
e7ce6f6136
commit
63fa595bfc
47 changed files with 1175 additions and 526 deletions
|
|
@ -1,9 +1,9 @@
|
|||
extern crate chrono;
|
||||
extern crate git2;
|
||||
|
||||
use std::io::Write;
|
||||
use std::fs::File;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@ extern crate serde_json;
|
|||
extern crate dreammaker as dm;
|
||||
extern crate dmm_tools;
|
||||
|
||||
use std::fmt;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
|
|
@ -62,9 +62,12 @@ impl Context {
|
|||
let environment: &std::path::Path = match opt.environment {
|
||||
Some(ref env) => env.as_ref(),
|
||||
None => match dm::detect_environment_default() {
|
||||
Ok(Some(found)) => { pathbuf = found; &pathbuf },
|
||||
Ok(Some(found)) => {
|
||||
pathbuf = found;
|
||||
&pathbuf
|
||||
}
|
||||
_ => dm::DEFAULT_ENV.as_ref(),
|
||||
}
|
||||
},
|
||||
};
|
||||
println!("parsing {}", environment.display());
|
||||
|
||||
|
|
@ -243,7 +246,12 @@ fn run(opt: &Opt, command: &Command, context: &mut Context) {
|
|||
context.dm_context.set_print_severity(Some(severity));
|
||||
context.procs = procs;
|
||||
context.objtree(opt);
|
||||
*context.exit_status.get_mut() = context.dm_context.errors().iter().filter(|e| e.severity() <= severity).count() as isize;
|
||||
*context.exit_status.get_mut() = context
|
||||
.dm_context
|
||||
.errors()
|
||||
.iter()
|
||||
.filter(|e| e.severity() <= severity)
|
||||
.count() as isize;
|
||||
},
|
||||
// --------------------------------------------------------------------
|
||||
Command::Minimap {
|
||||
|
|
@ -251,10 +259,23 @@ fn run(opt: &Opt, command: &Command, context: &mut Context) {
|
|||
pngcrush, optipng,
|
||||
} => {
|
||||
context.objtree(opt);
|
||||
if context.dm_context.errors().iter().filter(|e| e.severity() <= dm::Severity::Error).next().is_some() {
|
||||
if context
|
||||
.dm_context
|
||||
.errors()
|
||||
.iter()
|
||||
.filter(|e| e.severity() <= dm::Severity::Error)
|
||||
.next()
|
||||
.is_some()
|
||||
{
|
||||
println!("there were some parsing errors; render may be inaccurate")
|
||||
}
|
||||
let Context { ref objtree, ref icon_cache, ref exit_status, parallel, .. } = *context;
|
||||
let Context {
|
||||
ref objtree,
|
||||
ref icon_cache,
|
||||
ref exit_status,
|
||||
parallel,
|
||||
..
|
||||
} = *context;
|
||||
|
||||
let render_passes = &dmm_tools::render_passes::configure(enable, disable);
|
||||
let paths: Vec<&Path> = files.iter().map(|p| p.as_ref()).collect();
|
||||
|
|
@ -281,7 +302,11 @@ fn run(opt: &Opt, command: &Command, context: &mut Context) {
|
|||
|
||||
let (dim_x, dim_y, dim_z) = map.dim_xyz();
|
||||
let mut min = min.unwrap_or(CoordArg { x: 0, y: 0, z: 0 });
|
||||
let mut max = max.unwrap_or(CoordArg { x: dim_x + 1, y: dim_y + 1, z: dim_z + 1 });
|
||||
let mut max = max.unwrap_or(CoordArg {
|
||||
x: dim_x + 1,
|
||||
y: dim_y + 1,
|
||||
z: dim_z + 1,
|
||||
});
|
||||
min.x = clamp(min.x, 1, dim_x);
|
||||
min.y = clamp(min.y, 1, dim_y);
|
||||
min.z = clamp(min.z, 1, dim_z);
|
||||
|
|
@ -306,7 +331,12 @@ fn run(opt: &Opt, command: &Command, context: &mut Context) {
|
|||
exit_status.fetch_add(1, Ordering::Relaxed);
|
||||
return;
|
||||
}
|
||||
let outfile = format!("{}/{}-{}.png", output, path.file_stem().unwrap().to_string_lossy(), 1 + z);
|
||||
let outfile = format!(
|
||||
"{}/{}-{}.png",
|
||||
output,
|
||||
path.file_stem().unwrap().to_string_lossy(),
|
||||
1 + z
|
||||
);
|
||||
println!("{}saving {}", prefix, outfile);
|
||||
image.to_file(outfile.as_ref()).unwrap();
|
||||
if pngcrush {
|
||||
|
|
@ -449,13 +479,21 @@ impl std::str::FromStr for CoordArg {
|
|||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, String> {
|
||||
match s.split(",").map(|x| x.parse()).collect::<Result<Vec<_>, std::num::ParseIntError>>() {
|
||||
Ok(ref vec) if vec.len() == 2 => {
|
||||
Ok(CoordArg { x: vec[0], y: vec[1], z: 0 })
|
||||
}
|
||||
Ok(ref vec) if vec.len() == 3 => {
|
||||
Ok(CoordArg { x: vec[0], y: vec[1], z: vec[2] })
|
||||
}
|
||||
match s
|
||||
.split(",")
|
||||
.map(|x| x.parse())
|
||||
.collect::<Result<Vec<_>, std::num::ParseIntError>>()
|
||||
{
|
||||
Ok(ref vec) if vec.len() == 2 => Ok(CoordArg {
|
||||
x: vec[0],
|
||||
y: vec[1],
|
||||
z: 0,
|
||||
}),
|
||||
Ok(ref vec) if vec.len() == 3 => Ok(CoordArg {
|
||||
x: vec[0],
|
||||
y: vec[1],
|
||||
z: vec[2],
|
||||
}),
|
||||
Ok(_) => Err("must specify 2 or 3 coordinates".into()),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ extern crate git2;
|
|||
extern crate walkdir;
|
||||
#[macro_use] extern crate serde_derive;
|
||||
|
||||
mod template;
|
||||
mod markdown;
|
||||
mod template;
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::cell::RefCell;
|
||||
|
|
@ -45,12 +45,16 @@ fn main() -> Result<(), Box<std::error::Error>> {
|
|||
tera::Value::String(s) => Ok(s.len().into()),
|
||||
tera::Value::Array(a) => Ok(a.len().into()),
|
||||
tera::Value::Object(o) => Ok(o.len().into()),
|
||||
_ => Ok(0 .into()),
|
||||
_ => Ok(0.into()),
|
||||
});
|
||||
tera.register_filter("substring", |input, opts| match input {
|
||||
tera::Value::String(s) => {
|
||||
let start = opts.get("start").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
|
||||
let mut end = opts.get("end").and_then(|v| v.as_u64()).map(|s| s as usize).unwrap_or(s.len());
|
||||
let mut end = opts
|
||||
.get("end")
|
||||
.and_then(|v| v.as_u64())
|
||||
.map(|s| s as usize)
|
||||
.unwrap_or(s.len());
|
||||
if end > s.len() {
|
||||
end = s.len();
|
||||
}
|
||||
|
|
@ -110,7 +114,12 @@ fn main() -> Result<(), Box<std::error::Error>> {
|
|||
params = &[][..];
|
||||
is_variadic = false;
|
||||
}
|
||||
dm::preprocessor::Define::Function { docs: dc, params: macro_params, variadic, .. } => {
|
||||
dm::preprocessor::Define::Function {
|
||||
docs: dc,
|
||||
params: macro_params,
|
||||
variadic,
|
||||
..
|
||||
} => {
|
||||
docs = dc;
|
||||
has_params = true;
|
||||
params = macro_params;
|
||||
|
|
@ -122,8 +131,23 @@ fn main() -> Result<(), Box<std::error::Error>> {
|
|||
}
|
||||
let docs = DocBlock::parse(&docs.text());
|
||||
let module = module_entry(&mut modules, &context.file_path(range.start.file));
|
||||
module.items_wip.push((range.start.line, ModuleItem::Define { name, teaser: docs.teaser().to_owned() }));
|
||||
module.defines.insert(name, Define { docs, has_params, params, is_variadic, line: range.start.line });
|
||||
module.items_wip.push((
|
||||
range.start.line,
|
||||
ModuleItem::Define {
|
||||
name,
|
||||
teaser: docs.teaser().to_owned(),
|
||||
},
|
||||
));
|
||||
module.defines.insert(
|
||||
name,
|
||||
Define {
|
||||
docs,
|
||||
has_params,
|
||||
params,
|
||||
is_variadic,
|
||||
line: range.start.line,
|
||||
},
|
||||
);
|
||||
macro_count += 1;
|
||||
}
|
||||
|
||||
|
|
@ -162,10 +186,14 @@ fn main() -> Result<(), Box<std::error::Error>> {
|
|||
progress.update(&ty.path);
|
||||
|
||||
let mut parsed_type = ParsedType::default();
|
||||
parsed_type.name = ty.get().vars.get("name")
|
||||
parsed_type.name = ty
|
||||
.get()
|
||||
.vars
|
||||
.get("name")
|
||||
.and_then(|v| v.value.constant.as_ref())
|
||||
.and_then(|c| c.as_str())
|
||||
.unwrap_or("").into();
|
||||
.unwrap_or("")
|
||||
.into();
|
||||
|
||||
let mut anything = false;
|
||||
let mut substance = false;
|
||||
|
|
@ -234,11 +262,14 @@ fn main() -> Result<(), Box<std::error::Error>> {
|
|||
// file the type under its module as well
|
||||
if let Some(ref block) = parsed_type.docs {
|
||||
if let Some(module) = modules.get_mut(&module_path(&context.file_path(ty.location.file))) {
|
||||
module.items_wip.push((ty.location.line, ModuleItem::Type {
|
||||
path: ty.get().pretty_path(),
|
||||
teaser: block.teaser().to_owned(),
|
||||
substance: substance,
|
||||
}));
|
||||
module.items_wip.push((
|
||||
ty.location.line,
|
||||
ModuleItem::Type {
|
||||
path: ty.get().pretty_path(),
|
||||
teaser: block.teaser().to_owned(),
|
||||
substance: substance,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -305,7 +336,13 @@ fn main() -> Result<(), Box<std::error::Error>> {
|
|||
if count == 0 {
|
||||
println!("0 types");
|
||||
} else {
|
||||
println!("{}/{}/{} types ({}%)", substance_count, types_with_docs.len(), count, (types_with_docs.len() * 100 / count));
|
||||
println!(
|
||||
"{}/{}/{} types ({}%)",
|
||||
substance_count,
|
||||
types_with_docs.len(),
|
||||
count,
|
||||
(types_with_docs.len() * 100 / count)
|
||||
);
|
||||
}
|
||||
|
||||
ALL_TYPE_NAMES.with(|all| {
|
||||
|
|
@ -320,12 +357,14 @@ fn main() -> Result<(), Box<std::error::Error>> {
|
|||
template::save_resources(output_path)?;
|
||||
|
||||
let env_filename = environment.display().to_string();
|
||||
let world_name = objtree.find("/world")
|
||||
let world_name = objtree
|
||||
.find("/world")
|
||||
.and_then(|w| w.get().vars.get("name"))
|
||||
.and_then(|v| v.value.constant.as_ref())
|
||||
.and_then(|c| c.as_str())
|
||||
.unwrap_or("");
|
||||
let title = index_docs.as_ref()
|
||||
let title = index_docs
|
||||
.as_ref()
|
||||
.and_then(|(title, _)| title.as_ref())
|
||||
.map(|s| &s[..])
|
||||
.unwrap_or(world_name);
|
||||
|
|
@ -489,7 +528,12 @@ fn linkify_type<'a, I: Iterator<Item=&'a str>>(iter: I) -> String {
|
|||
progress.push_str(bit);
|
||||
if ALL_TYPE_NAMES.with(|t| t.borrow().contains(&all_progress)) {
|
||||
use std::fmt::Write;
|
||||
let _ = write!(output, r#"/<a href="{}.html">{}</a>"#, &all_progress[1..], &progress[1..]);
|
||||
let _ = write!(
|
||||
output,
|
||||
r#"/<a href="{}.html">{}</a>"#,
|
||||
&all_progress[1..],
|
||||
&progress[1..]
|
||||
);
|
||||
progress.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -526,10 +570,15 @@ fn create(path: &Path) -> io::Result<File> {
|
|||
|
||||
fn git_info(git: &mut Git) -> Result<(), git2::Error> {
|
||||
macro_rules! req {
|
||||
($e:expr) => { match $e { Some(x) => x, None => {
|
||||
println!("incomplete git info: malformed or non-utf8 name");
|
||||
return Ok(());
|
||||
}}}
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
println!("incomplete git info: malformed or non-utf8 name");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// get the revision
|
||||
|
|
@ -582,7 +631,7 @@ fn git_info(git: &mut Git) -> Result<(), git2::Error> {
|
|||
let at = req!(url.find("@"));
|
||||
let colon = req!(url.find(":"));
|
||||
if colon >= at {
|
||||
git.web_url = format!("https://{}/{}", &url[at+1..colon], &url[colon+1..]);
|
||||
git.web_url = format!("https://{}/{}", &url[at + 1..colon], &url[colon + 1..]);
|
||||
} else {
|
||||
println!("incomplete git info: weird SSH path: {}", url);
|
||||
}
|
||||
|
|
@ -599,7 +648,7 @@ struct Progress {
|
|||
impl Progress {
|
||||
fn update(&mut self, msg: &str) {
|
||||
print!("\r{}", msg);
|
||||
for _ in msg.len() .. self.last_len {
|
||||
for _ in msg.len()..self.last_len {
|
||||
print!(" ");
|
||||
}
|
||||
self.last_len = msg.len();
|
||||
|
|
@ -635,7 +684,8 @@ struct IndexTree<'a> {
|
|||
}
|
||||
|
||||
fn build_index_tree<'a, I>(iter: I) -> Vec<IndexTree<'a>>
|
||||
where I: IntoIterator<Item=IndexTree<'a>>
|
||||
where
|
||||
I: IntoIterator<Item=IndexTree<'a>>,
|
||||
{
|
||||
let mut stack = vec![IndexTree {
|
||||
htmlname: "",
|
||||
|
|
|
|||
|
|
@ -25,22 +25,25 @@ impl DocBlock {
|
|||
|
||||
pub fn parse_with_title(markdown: &str) -> (Option<String>, Self) {
|
||||
let mut parser = parser(markdown).peekable();
|
||||
(if let Some(&Event::Start(Tag::Header(1))) = parser.peek() {
|
||||
parser.next();
|
||||
let mut pieces = Vec::new();
|
||||
loop {
|
||||
match parser.next() {
|
||||
None | Some(Event::End(Tag::Header(1))) => break,
|
||||
Some(other) => pieces.push(other),
|
||||
(
|
||||
if let Some(&Event::Start(Tag::Header(1))) = parser.peek() {
|
||||
parser.next();
|
||||
let mut pieces = Vec::new();
|
||||
loop {
|
||||
match parser.next() {
|
||||
None | Some(Event::End(Tag::Header(1))) => break,
|
||||
Some(other) => pieces.push(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut title = String::new();
|
||||
push_html(&mut title, pieces);
|
||||
Some(title)
|
||||
} else {
|
||||
None
|
||||
}, parse_main(parser))
|
||||
let mut title = String::new();
|
||||
push_html(&mut title, pieces);
|
||||
Some(title)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
parse_main(parser),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn teaser(&self) -> &str {
|
||||
|
|
@ -52,7 +55,7 @@ fn parser(markdown: &str) -> Parser {
|
|||
Parser::new_with_broken_link_callback(
|
||||
markdown,
|
||||
pulldown_cmark::OPTION_ENABLE_TABLES,
|
||||
Some(&::handle_crosslink)
|
||||
Some(&::handle_crosslink),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -216,7 +216,10 @@ pub struct Prefab<E=Expression> {
|
|||
|
||||
impl<E> From<TypePath> for Prefab<E> {
|
||||
fn from(path: TypePath) -> Self {
|
||||
Prefab { path, vars: Default::default() }
|
||||
Prefab {
|
||||
path,
|
||||
vars: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -324,7 +327,7 @@ impl Expression {
|
|||
None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -337,7 +340,7 @@ impl From<Term> for Expression {
|
|||
unary: vec![],
|
||||
follow: vec![],
|
||||
term,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -406,7 +409,7 @@ impl From<Expression> for Term {
|
|||
} else {
|
||||
Term::Expr(Box::new(Expression::Base { term, unary, follow }))
|
||||
},
|
||||
other => Term::Expr(Box::new(other))
|
||||
other => Term::Expr(Box::new(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -567,20 +570,28 @@ impl VarType {
|
|||
impl FromIterator<String> for VarType {
|
||||
fn from_iter<T: IntoIterator<Item=String>>(iter: T) -> Self {
|
||||
let (mut is_static, mut is_const, mut is_tmp) = (false, false, false);
|
||||
let type_path = iter.into_iter()
|
||||
let type_path = iter
|
||||
.into_iter()
|
||||
.skip_while(|p| {
|
||||
if p == "global" || p == "static" {
|
||||
is_static = true; true
|
||||
is_static = true;
|
||||
true
|
||||
} else if p == "const" {
|
||||
is_const = true; true
|
||||
is_const = true;
|
||||
true
|
||||
} else if p == "tmp" {
|
||||
is_tmp = true; true
|
||||
is_tmp = true;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
VarType { is_static, is_const, is_tmp, type_path }
|
||||
}).collect();
|
||||
VarType {
|
||||
is_static,
|
||||
is_const,
|
||||
is_tmp,
|
||||
type_path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,10 +150,14 @@ pub fn register_builtins(tree: &mut ObjectTree) -> Result<(), DMError> {
|
|||
}
|
||||
}
|
||||
macro_rules! int {
|
||||
($e:expr) => {Expression::from(Term::Int($e))}
|
||||
($e:expr) => {
|
||||
Expression::from(Term::Int($e))
|
||||
};
|
||||
}
|
||||
macro_rules! string {
|
||||
($e:expr) => {Expression::from(Term::String($e.into()))}
|
||||
($e:expr) => {
|
||||
Expression::from(Term::String($e.into()))
|
||||
};
|
||||
}
|
||||
|
||||
entries! {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ impl Constant {
|
|||
if key == k {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
false
|
||||
|
|
@ -84,7 +84,7 @@ impl Constant {
|
|||
if key == k {
|
||||
return v.as_ref();
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
|
|
@ -263,8 +263,16 @@ pub(crate) fn evaluate_all(context: &Context, tree: &mut ObjectTree, sloppy: boo
|
|||
for ty in tree.graph.node_indices() {
|
||||
let keys: Vec<String> = tree.graph.node_weight(ty).unwrap().vars.keys().cloned().collect();
|
||||
for key in keys {
|
||||
if !tree.graph.node_weight(ty).unwrap().get_declaration(&key, tree).map_or(true, |x| x.var_type.is_const_evaluable() && (x.var_type.is_const || ty != NodeIndex::new(0))) {
|
||||
continue // skip non-constant-evaluable vars
|
||||
if !tree
|
||||
.graph
|
||||
.node_weight(ty)
|
||||
.unwrap()
|
||||
.get_declaration(&key, tree)
|
||||
.map_or(true, |x| {
|
||||
x.var_type.is_const_evaluable() && (x.var_type.is_const || ty != NodeIndex::new(0))
|
||||
})
|
||||
{
|
||||
continue; // skip non-constant-evaluable vars
|
||||
}
|
||||
match constant_ident_lookup(tree, ty, &key, false) {
|
||||
Err(err) => context.register_error(err),
|
||||
|
|
@ -280,8 +288,15 @@ pub(crate) fn evaluate_all(context: &Context, tree: &mut ObjectTree, sloppy: boo
|
|||
""
|
||||
};
|
||||
|
||||
context.register_error(DMError::new(tree.graph.node_weight(ty).unwrap().vars[&key].value.location,
|
||||
format!("undefined var '{}' on type '{}'{}", key, tree.graph.node_weight(ty).unwrap().path, extra)));
|
||||
context.register_error(DMError::new(
|
||||
tree.graph.node_weight(ty).unwrap().vars[&key].value.location,
|
||||
format!(
|
||||
"undefined var '{}' on type '{}'{}",
|
||||
key,
|
||||
tree.graph.node_weight(ty).unwrap().path,
|
||||
extra
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -290,12 +305,22 @@ pub(crate) fn evaluate_all(context: &Context, tree: &mut ObjectTree, sloppy: boo
|
|||
|
||||
/// Evaluate an expression in the absence of any surrounding context.
|
||||
pub fn simple_evaluate(location: Location, expr: Expression) -> Result<Constant, DMError> {
|
||||
ConstantFolder { tree: None, location, ty: NodeIndex::new(0), defines: None }.expr(expr, None)
|
||||
ConstantFolder {
|
||||
tree: None,
|
||||
location,
|
||||
ty: NodeIndex::new(0),
|
||||
defines: None,
|
||||
}.expr(expr, None)
|
||||
}
|
||||
|
||||
/// Evaluate an expression in the preprocessor, with `defined()` available.
|
||||
pub fn preprocessor_evaluate(location: Location, expr: Expression, defines: &DefineMap) -> Result<Constant, DMError> {
|
||||
ConstantFolder { tree: None, location, ty: NodeIndex::new(0), defines: Some(defines) }.expr(expr, None)
|
||||
ConstantFolder {
|
||||
tree: None,
|
||||
location,
|
||||
ty: NodeIndex::new(0),
|
||||
defines: Some(defines),
|
||||
}.expr(expr, None)
|
||||
}
|
||||
|
||||
enum ConstLookup {
|
||||
|
|
@ -303,29 +328,49 @@ enum ConstLookup {
|
|||
Continue(Option<NodeIndex>),
|
||||
}
|
||||
|
||||
fn constant_ident_lookup(tree: &mut ObjectTree, ty: NodeIndex, ident: &str, must_be_static: bool) -> Result<ConstLookup, DMError> {
|
||||
fn constant_ident_lookup(
|
||||
tree: &mut ObjectTree,
|
||||
ty: NodeIndex,
|
||||
ident: &str,
|
||||
must_be_static: bool,
|
||||
) -> Result<ConstLookup, DMError> {
|
||||
// try to read the currently-set value if we can and
|
||||
// substitute that in, otherwise try to evaluate it.
|
||||
let (location, type_hint, expr) = {
|
||||
let decl = match tree.graph.node_weight(ty).unwrap().get_declaration(ident, tree).cloned() {
|
||||
let decl = match tree
|
||||
.graph
|
||||
.node_weight(ty)
|
||||
.unwrap()
|
||||
.get_declaration(ident, tree)
|
||||
.cloned()
|
||||
{
|
||||
Some(decl) => decl,
|
||||
None => return Ok(ConstLookup::Continue(None)) // definitely doesn't exist
|
||||
None => return Ok(ConstLookup::Continue(None)), // definitely doesn't exist
|
||||
};
|
||||
|
||||
let type_ = tree.graph.node_weight_mut(ty).unwrap();
|
||||
let parent = type_.parent_type();
|
||||
match type_.vars.get_mut(ident) {
|
||||
None => { return Ok(ConstLookup::Continue(parent)); }
|
||||
None => return Ok(ConstLookup::Continue(parent)),
|
||||
Some(var) => match var.value.constant.clone() {
|
||||
Some(constant) => { return Ok(ConstLookup::Found(decl.var_type.type_path.clone(), constant)); }
|
||||
Some(constant) => return Ok(ConstLookup::Found(decl.var_type.type_path.clone(), constant)),
|
||||
None => match var.value.expression.clone() {
|
||||
Some(expr) => {
|
||||
if var.value.being_evaluated {
|
||||
return Err(DMError::new(var.value.location, format!("recursive constant reference: {}", ident)));
|
||||
return Err(DMError::new(
|
||||
var.value.location,
|
||||
format!("recursive constant reference: {}", ident),
|
||||
));
|
||||
} else if !decl.var_type.is_const_evaluable() {
|
||||
return Err(DMError::new(var.value.location, format!("non-const variable: {}", ident)));
|
||||
return Err(DMError::new(
|
||||
var.value.location,
|
||||
format!("non-const variable: {}", ident),
|
||||
));
|
||||
} else if !decl.var_type.is_static && must_be_static {
|
||||
return Err(DMError::new(var.value.location, format!("non-static variable: {}", ident)));
|
||||
return Err(DMError::new(
|
||||
var.value.location,
|
||||
format!("non-static variable: {}", ident),
|
||||
));
|
||||
}
|
||||
var.value.being_evaluated = true;
|
||||
(var.value.location, decl.var_type.type_path, expr)
|
||||
|
|
@ -335,13 +380,17 @@ fn constant_ident_lookup(tree: &mut ObjectTree, ty: NodeIndex, ident: &str, must
|
|||
var.value.constant = Some(c.clone());
|
||||
return Ok(ConstLookup::Found(decl.var_type.type_path, c));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
};
|
||||
// evaluate full_value
|
||||
let value = ConstantFolder { tree: Some(tree), defines: None, location, ty }
|
||||
.expr(expr, if type_hint.is_empty() { None } else { Some(&type_hint) })?;
|
||||
let value = ConstantFolder {
|
||||
tree: Some(tree),
|
||||
defines: None,
|
||||
location,
|
||||
ty,
|
||||
}.expr(expr, if type_hint.is_empty() { None } else { Some(&type_hint) })?;
|
||||
// and store it into 'value', then return it
|
||||
let var = tree.graph.node_weight_mut(ty).unwrap().vars.get_mut(ident).unwrap();
|
||||
var.value.constant = Some(value.clone());
|
||||
|
|
@ -366,7 +415,11 @@ impl<'a> ConstantFolder<'a> {
|
|||
fn expr(&mut self, expression: Expression, type_hint: Option<&TreePath>) -> Result<Constant, DMError> {
|
||||
Ok(match expression {
|
||||
Expression::Base { unary, term, follow } => {
|
||||
let base_type_hint = if follow.is_empty() && unary.is_empty() { type_hint } else { None };
|
||||
let base_type_hint = if follow.is_empty() && unary.is_empty() {
|
||||
type_hint
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut term = self.term(term, base_type_hint)?;
|
||||
for each in follow {
|
||||
term = self.follow(term, each)?;
|
||||
|
|
@ -407,7 +460,11 @@ impl<'a> ConstantFolder<'a> {
|
|||
for each in v {
|
||||
out.push(match each {
|
||||
// handle associations
|
||||
Expression::AssignOp { op: AssignOp::Assign, lhs, rhs } => {
|
||||
Expression::AssignOp {
|
||||
op: AssignOp::Assign,
|
||||
lhs,
|
||||
rhs,
|
||||
} => {
|
||||
let key = match Term::from(*lhs) {
|
||||
Term::Ident(ident) => Constant::String(ident),
|
||||
other => self.term(other, None)?,
|
||||
|
|
@ -439,7 +496,7 @@ impl<'a> ConstantFolder<'a> {
|
|||
None => Err(self.error(format!("unknown typepath {}", full_path))),
|
||||
}
|
||||
}
|
||||
(term, follow) => Err(self.error(format!("non-constant expression follower: {} {:?}", term, follow)))
|
||||
(term, follow) => Err(self.error(format!("non-constant expression follower: {} {:?}", term, follow))),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -487,12 +544,15 @@ impl<'a> ConstantFolder<'a> {
|
|||
if rhs >= 2 && (i32::max_value() as f32).log(lhs as f32) < rhs as f32 {
|
||||
return Err(self.error(format!("out-of-range {:?}: {} {} {}", op, lhs, op, rhs)));
|
||||
}
|
||||
return Ok(Constant::from(lhs.pow(rhs as u32)))
|
||||
return Ok(Constant::from(lhs.pow(rhs as u32)));
|
||||
}
|
||||
(BinaryOp::Pow, Int(lhs), Float(rhs)) => return Ok(Constant::from((lhs as f32).powf(rhs.raw()))),
|
||||
(BinaryOp::Pow, Float(lhs), Int(rhs)) => return Ok(Constant::from(lhs.powi(rhs))),
|
||||
(BinaryOp::Pow, Float(lhs), Float(rhs)) => return Ok(Constant::from(lhs.powf(rhs))),
|
||||
(_, lhs_, rhs_) => { lhs = lhs_; rhs = rhs_; }
|
||||
(_, lhs_, rhs_) => {
|
||||
lhs = lhs_;
|
||||
rhs = rhs_;
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! integer {
|
||||
|
|
@ -515,29 +575,25 @@ impl<'a> ConstantFolder<'a> {
|
|||
(BinaryOp::NotEq, lhs, rhs) => Ok(Constant::from(lhs != rhs)),
|
||||
(BinaryOp::And, lhs, rhs) => Ok(if lhs.to_bool() { rhs } else { lhs }),
|
||||
(BinaryOp::Or, lhs, rhs) => Ok(if lhs.to_bool() { lhs } else { rhs }),
|
||||
(op, lhs, rhs) => Err(self.error(format!("non-constant {:?}: {} {} {}", op, lhs, op, rhs)))
|
||||
(op, lhs, rhs) => Err(self.error(format!("non-constant {:?}: {} {} {}", op, lhs, op, rhs))),
|
||||
}
|
||||
}
|
||||
|
||||
fn term(&mut self, term: Term, type_hint: Option<&TreePath>) -> Result<Constant, DMError> {
|
||||
Ok(match term {
|
||||
Term::Null => Constant::Null(type_hint.cloned()),
|
||||
Term::New { type_, args } => {
|
||||
Constant::New {
|
||||
type_: match type_ {
|
||||
NewType::Prefab(e) => NewType::Prefab(self.prefab(e)?),
|
||||
NewType::Implicit => NewType::Implicit,
|
||||
NewType::Ident(_) => return Err(self.error("non-constant new expression")),
|
||||
},
|
||||
args: match args {
|
||||
Some(args) => Some(self.arguments(args)?),
|
||||
None => None,
|
||||
},
|
||||
}
|
||||
},
|
||||
Term::List(vec) => {
|
||||
Constant::List(self.arguments(vec)?)
|
||||
Term::New { type_, args } => Constant::New {
|
||||
type_: match type_ {
|
||||
NewType::Prefab(e) => NewType::Prefab(self.prefab(e)?),
|
||||
NewType::Implicit => NewType::Implicit,
|
||||
NewType::Ident(_) => return Err(self.error("non-constant new expression")),
|
||||
},
|
||||
args: match args {
|
||||
Some(args) => Some(self.arguments(args)?),
|
||||
None => None,
|
||||
},
|
||||
},
|
||||
Term::List(vec) => Constant::List(self.arguments(vec)?),
|
||||
Term::Call(ident, args) => match &*ident {
|
||||
// constructors which remain as they are
|
||||
"matrix" => Constant::Call(ConstFn::Matrix, self.arguments(args)?),
|
||||
|
|
@ -573,11 +629,11 @@ impl<'a> ConstantFolder<'a> {
|
|||
=> {
|
||||
Constant::Int(if defines.contains_key(ident) { 1 } else { 0 })
|
||||
}
|
||||
_ => return Err(self.error("malformed defined() call"))
|
||||
_ => return Err(self.error("malformed defined() call")),
|
||||
}
|
||||
}
|
||||
// other functions are no-goes
|
||||
_ => return Err(self.error(format!("non-constant function call: {}", ident)))
|
||||
_ => return Err(self.error(format!("non-constant function call: {}", ident))),
|
||||
},
|
||||
Term::Prefab(prefab) => Constant::Prefab(self.prefab(prefab)?),
|
||||
Term::Ident(ident) => self.ident(ident, false)?,
|
||||
|
|
@ -586,7 +642,7 @@ impl<'a> ConstantFolder<'a> {
|
|||
Term::Int(v) => Constant::Int(v),
|
||||
Term::Float(v) => Constant::from(v),
|
||||
Term::Expr(expr) => self.expr(*expr, type_hint)?,
|
||||
_ => return Err(self.error(format!("non-constant expression")))
|
||||
_ => return Err(self.error(format!("non-constant expression"))),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -596,7 +652,10 @@ impl<'a> ConstantFolder<'a> {
|
|||
// TODO: find a type annotation by looking up 'k' on the prefab's type
|
||||
vars.insert(k, self.expr(v, None)?);
|
||||
}
|
||||
Ok(Prefab { path: prefab.path, vars })
|
||||
Ok(Prefab {
|
||||
path: prefab.path,
|
||||
vars,
|
||||
})
|
||||
}
|
||||
|
||||
fn ident(&mut self, ident: String, must_be_static: bool) -> Result<Constant, DMError> {
|
||||
|
|
@ -612,7 +671,9 @@ impl<'a> ConstantFolder<'a> {
|
|||
return Err(self.error("cannot reference variables in this context"));
|
||||
}
|
||||
let tree = self.tree.as_mut().unwrap();
|
||||
match constant_ident_lookup(tree, ty, &ident, must_be_static).map_err(|e| DMError::new(location, e.into_description()))? {
|
||||
match constant_ident_lookup(tree, ty, &ident, must_be_static)
|
||||
.map_err(|e| DMError::new(location, e.into_description()))?
|
||||
{
|
||||
ConstLookup::Found(_, v) => return Ok(v),
|
||||
ConstLookup::Continue(i) => idx = i,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ fn parse_metadata(data: &str) -> Metadata {
|
|||
|
||||
for line in lines {
|
||||
if line.starts_with("# END DMI") {
|
||||
break
|
||||
break;
|
||||
}
|
||||
let mut split = line.trim().splitn(2, " = ");
|
||||
let key = split.next().unwrap();
|
||||
|
|
@ -201,7 +201,7 @@ fn parse_metadata(data: &str) -> Metadata {
|
|||
vector.truncate(n);
|
||||
state.frames = Frames::Delays(vector);
|
||||
},
|
||||
Frames::Delays(_) => panic!()
|
||||
Frames::Delays(_) => panic!(),
|
||||
}
|
||||
}
|
||||
"loop" => state.as_mut().unwrap().loop_ = value.parse().unwrap(),
|
||||
|
|
|
|||
|
|
@ -69,7 +69,11 @@ pub struct DocComment {
|
|||
impl DocComment {
|
||||
/// Construct an empty DocComment with the given properties.
|
||||
pub fn new(kind: CommentKind, target: DocTarget) -> DocComment {
|
||||
DocComment { kind, target, text: String::new() }
|
||||
DocComment {
|
||||
kind,
|
||||
target,
|
||||
text: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if this comment is entirely textless.
|
||||
|
|
@ -121,7 +125,9 @@ fn simplify(out: &mut String, text: &str, ignore_char: char) -> bool {
|
|||
continue;
|
||||
}
|
||||
|
||||
let this_prefix = &line[..line.len() - line.trim_left_matches(|c: char| c.is_whitespace() || c == ignore_char).len()];
|
||||
let this_prefix = &line[..line.len() - line
|
||||
.trim_left_matches(|c: char| c.is_whitespace() || c == ignore_char)
|
||||
.len()];
|
||||
match prefix {
|
||||
None => prefix = Some(this_prefix),
|
||||
Some(ref mut prefix) => {
|
||||
|
|
@ -130,7 +136,9 @@ fn simplify(out: &mut String, text: &str, ignore_char: char) -> bool {
|
|||
loop {
|
||||
no_match = chars.as_str();
|
||||
match chars.next() {
|
||||
Some(ch) => if Some(ch) != this_chars.next() { break },
|
||||
Some(ch) => if Some(ch) != this_chars.next() {
|
||||
break;
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
|
@ -147,7 +155,9 @@ fn simplify(out: &mut String, text: &str, ignore_char: char) -> bool {
|
|||
loop {
|
||||
no_match = chars.as_str();
|
||||
match chars.next_back() {
|
||||
Some(ch) => if Some(ch) != this_chars.next_back() { break },
|
||||
Some(ch) => if Some(ch) != this_chars.next_back() {
|
||||
break;
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
|
|
@ -174,7 +184,7 @@ fn simplify(out: &mut String, text: &str, ignore_char: char) -> bool {
|
|||
for _ in 0..newlines {
|
||||
out.push_str("\n");
|
||||
}
|
||||
out.push_str(&line[prefix_len..line.len()-suffix_len]);
|
||||
out.push_str(&line[prefix_len..line.len() - suffix_len]);
|
||||
anything = true;
|
||||
newlines = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@ impl Context {
|
|||
if let Some(severity) = self.print_severity {
|
||||
if error.severity <= severity {
|
||||
let stderr = io::stderr();
|
||||
self.pretty_print_error(&mut stderr.lock(), &error).expect("error writing to stderr");
|
||||
self.pretty_print_error(&mut stderr.lock(), &error)
|
||||
.expect("error writing to stderr");
|
||||
}
|
||||
}
|
||||
self.errors.borrow_mut().push(error);
|
||||
|
|
@ -99,10 +100,13 @@ impl Context {
|
|||
|
||||
/// Pretty-print a `DMError` to the given output.
|
||||
pub fn pretty_print_error<W: io::Write>(&self, w: &mut W, error: &DMError) -> io::Result<()> {
|
||||
writeln!(w, "{}, line {}, column {}:",
|
||||
writeln!(
|
||||
w,
|
||||
"{}, line {}, column {}:",
|
||||
self.file_path(error.location.file).display(),
|
||||
error.location.line,
|
||||
error.location.column)?;
|
||||
error.location.column,
|
||||
)?;
|
||||
writeln!(w, "{}: {}\n", error.severity, error.description)
|
||||
}
|
||||
|
||||
|
|
@ -188,11 +192,15 @@ pub trait HasLocation {
|
|||
}
|
||||
|
||||
impl<'a, T: HasLocation> HasLocation for &'a T {
|
||||
fn location(&self) -> Location { (**self).location() }
|
||||
fn location(&self) -> Location {
|
||||
(**self).location()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: HasLocation> HasLocation for &'a mut T {
|
||||
fn location(&self) -> Location { (**self).location() }
|
||||
fn location(&self) -> Location {
|
||||
(**self).location()
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -14,8 +14,22 @@ fn main() {
|
|||
println!("---- item_flags example ----");
|
||||
objtree.find("/obj/item").expect("no root").recurse(&mut |ty| {
|
||||
print!("{}: ", ty.path);
|
||||
let mut flags_1 = ty.get_value("flags_1").expect("flags_1").constant.as_ref().expect("f1c").to_int().unwrap_or(0);
|
||||
let mut item_flags = ty.get_value("item_flags").expect("item_flags").constant.as_ref().expect("ofc").to_int().unwrap_or(0);
|
||||
let mut flags_1 = ty
|
||||
.get_value("flags_1")
|
||||
.expect("flags_1")
|
||||
.constant
|
||||
.as_ref()
|
||||
.expect("f1c")
|
||||
.to_int()
|
||||
.unwrap_or(0);
|
||||
let mut item_flags = ty
|
||||
.get_value("item_flags")
|
||||
.expect("item_flags")
|
||||
.constant
|
||||
.as_ref()
|
||||
.expect("ofc")
|
||||
.to_int()
|
||||
.unwrap_or(0);
|
||||
|
||||
// Migrate old flags_1 values to their item_flags equivalents
|
||||
let lhs =
|
||||
|
|
@ -29,14 +43,20 @@ fn main() {
|
|||
item_flags &= !rhs;
|
||||
|
||||
let crossover = if rhs != 0 && lhs != 0 {
|
||||
panic!("flags_1={}, item_flags={}, lhs={}, rhs={}", flags_1, item_flags, lhs, rhs);
|
||||
panic!(
|
||||
"flags_1={}, item_flags={}, lhs={}, rhs={}",
|
||||
flags_1, item_flags, lhs, rhs
|
||||
);
|
||||
} else if lhs != 0 {
|
||||
lhs
|
||||
} else {
|
||||
rhs
|
||||
};
|
||||
|
||||
println!("flags_1={}, item_flags={}, crossover={}", flags_1, item_flags, crossover);
|
||||
println!(
|
||||
"flags_1={}, item_flags={}, crossover={}",
|
||||
flags_1, item_flags, crossover
|
||||
);
|
||||
});
|
||||
|
||||
println!("---- anchored example ----");
|
||||
|
|
@ -50,7 +70,16 @@ fn main() {
|
|||
println!("{} -> {}", ty.path, anch);
|
||||
|
||||
// print location info for any type with a redundant `anchored = TRUE`
|
||||
if anch && ty.parent_type().unwrap().get_value("anchored").unwrap().constant.as_ref().unwrap().to_bool() {
|
||||
if anch && ty
|
||||
.parent_type()
|
||||
.unwrap()
|
||||
.get_value("anchored")
|
||||
.unwrap()
|
||||
.constant
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.to_bool()
|
||||
{
|
||||
println!("{}:{}", ctx.file_path(var.location.file).display(), var.location.line);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -123,7 +123,9 @@ impl<'ctx, I> IndentProcessor<'ctx, I> where
|
|||
// hope that truncating division will approximate
|
||||
// a sane situation.
|
||||
self.context.register_error(self.error(format!(
|
||||
"inconsistent indentation: {} % {} != 0", spaces, spaces_per_indent)));
|
||||
"inconsistent indentation: {} % {} != 0",
|
||||
spaces, spaces_per_indent
|
||||
)));
|
||||
}
|
||||
new_indents = spaces / spaces_per_indent;
|
||||
self.current = Some((spaces_per_indent, new_indents));
|
||||
|
|
@ -137,7 +139,9 @@ impl<'ctx, I> IndentProcessor<'ctx, I> where
|
|||
} else if indents < new_indents {
|
||||
// multiple indent is an error, register it but let it work
|
||||
self.context.register_error(self.error(format!(
|
||||
"inconsistent multiple indentation: {} > 1", new_indents - indents)));
|
||||
"inconsistent multiple indentation: {} > 1",
|
||||
new_indents - indents,
|
||||
)));
|
||||
for _ in indents..new_indents {
|
||||
self.push_eol(Token::Punct(Punctuation::LBrace));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,12 +160,17 @@ static SPEEDY_TABLE: [(usize, usize); 127] = [
|
|||
|
||||
#[test]
|
||||
fn make_speedy_table() {
|
||||
let everything: Vec<&str> = PUNCT_TABLE.iter()
|
||||
let everything: Vec<&str> = PUNCT_TABLE
|
||||
.iter()
|
||||
.map(|p| p.0)
|
||||
.filter(|s| !s.chars().any(|c| c.is_alphanumeric()))
|
||||
.collect();
|
||||
for each in everything.iter() {
|
||||
assert!(each.len() == 1 || everything.contains(&&each[..each.len() - 1]), "no prefix: {}", each);
|
||||
assert!(
|
||||
each.len() == 1 || everything.contains(&&each[..each.len() - 1]),
|
||||
"no prefix: {}",
|
||||
each
|
||||
);
|
||||
}
|
||||
|
||||
let mut table = vec![];
|
||||
|
|
@ -189,7 +194,11 @@ fn make_speedy_table() {
|
|||
}
|
||||
|
||||
if &SPEEDY_TABLE[..] != &table[..] {
|
||||
panic!("\n\nSpeedy table outdated, replace with:\n\nstatic SPEEDY_TABLE: [(usize, usize); {}] = {:?};\n\n", table.len(), table);
|
||||
panic!(
|
||||
"\n\nSpeedy table outdated, replace with:\n\nstatic SPEEDY_TABLE: [(usize, usize); {}] = {:?};\n\n",
|
||||
table.len(),
|
||||
table
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -526,9 +535,7 @@ impl<I: Iterator<Item=io::Result<u8>>> Iterator for LocationTracker<I> {
|
|||
}
|
||||
Some(Ok(ch))
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
Some(Err(DMError::new(self.location, "i/o error").set_cause(e)))
|
||||
}
|
||||
Some(Err(e)) => Some(Err(DMError::new(self.location, "i/o error").set_cause(e))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -673,7 +680,10 @@ impl<'ctx, I: Iterator<Item=io::Result<u8>>> Lexer<'ctx, I> {
|
|||
match self.next() {
|
||||
Some(b'/') => comment = Some(DocComment::new(CommentKind::Line, DocTarget::FollowingItem)),
|
||||
Some(b'!') => comment = Some(DocComment::new(CommentKind::Line, DocTarget::EnclosingItem)),
|
||||
Some(b'\n') => { self.put_back(Some(b'\n')); return None },
|
||||
Some(b'\n') => {
|
||||
self.put_back(Some(b'\n'));
|
||||
return None;
|
||||
}
|
||||
Some(b'\\') => backslash = true,
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -798,7 +808,10 @@ impl<'ctx, I: Iterator<Item=io::Result<u8>>> Lexer<'ctx, I> {
|
|||
loop {
|
||||
match self.next() {
|
||||
Some(ch) if is_ident(ch) || is_digit(ch) => ident.push(ch),
|
||||
ch => { self.put_back(ch); break }
|
||||
ch => {
|
||||
self.put_back(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
from_latin1(ident)
|
||||
|
|
@ -838,9 +851,9 @@ impl<'ctx, I: Iterator<Item=io::Result<u8>>> Lexer<'ctx, I> {
|
|||
if ch == end[idx] && !backslash {
|
||||
idx += 1;
|
||||
if idx == end.len() {
|
||||
break
|
||||
break;
|
||||
}
|
||||
continue
|
||||
continue;
|
||||
} else if ch == end[0] && !backslash {
|
||||
// TODO: this is a hack to fix the '""}' situation
|
||||
buf.extend_from_slice(&end[..idx]);
|
||||
|
|
@ -899,7 +912,7 @@ impl<'ctx, I: Iterator<Item=io::Result<u8>>> Lexer<'ctx, I> {
|
|||
candidate = Some(items[0].1);
|
||||
}
|
||||
if items.len() == 1 {
|
||||
return candidate
|
||||
return candidate;
|
||||
}
|
||||
|
||||
match self.next() {
|
||||
|
|
@ -967,7 +980,7 @@ impl<'ctx, I: Iterator<Item=io::Result<u8>>> Iterator for Lexer<'ctx, I> {
|
|||
return Some(LocatedToken {
|
||||
location: location,
|
||||
token: Token::Punct(Punctuation::Newline),
|
||||
})
|
||||
});
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -1047,7 +1060,7 @@ impl<'ctx, I: Iterator<Item=io::Result<u8>>> Iterator for Lexer<'ctx, I> {
|
|||
// check keywords
|
||||
for &(name, value) in PUNCT_TABLE.iter() {
|
||||
if name == ident {
|
||||
return Some(locate(Punct(value)))
|
||||
return Some(locate(Punct(value)));
|
||||
}
|
||||
}
|
||||
self.close_allowed = true;
|
||||
|
|
@ -1066,8 +1079,8 @@ impl<'ctx, I: Iterator<Item=io::Result<u8>>> Iterator for Lexer<'ctx, I> {
|
|||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ macro_rules! try_iter {
|
|||
Ok(x) => x,
|
||||
Err(e) => return Some(Err(From::from(e))),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod error;
|
||||
|
|
@ -72,17 +72,23 @@ pub fn pretty_print<W, I>(w: &mut W, input: I, show_ws: bool) -> io::Result<()>
|
|||
lexer::Token::Punct(lexer::Punctuation::LBrace) => {
|
||||
indents += 1;
|
||||
needs_newline = true;
|
||||
if show_ws { write!(w, "{{")?; }
|
||||
if show_ws {
|
||||
write!(w, "{{")?;
|
||||
}
|
||||
}
|
||||
lexer::Token::Punct(lexer::Punctuation::RBrace) => {
|
||||
indents -= 1;
|
||||
needs_newline = true;
|
||||
if show_ws { write!(w, "}}")?; }
|
||||
if show_ws {
|
||||
write!(w, "}}")?;
|
||||
}
|
||||
}
|
||||
lexer::Token::Punct(lexer::Punctuation::Semicolon) |
|
||||
lexer::Token::Punct(lexer::Punctuation::Newline) => {
|
||||
needs_newline = true;
|
||||
if show_ws { write!(w, ";")?; }
|
||||
if show_ws {
|
||||
write!(w, ";")?;
|
||||
}
|
||||
}
|
||||
lexer::Token::DocComment(_) => {}
|
||||
other => {
|
||||
|
|
|
|||
|
|
@ -163,7 +163,11 @@ impl<'a> TypeRef<'a> {
|
|||
|
||||
/// Find the parent **path**, without taking `parent_type` into account.
|
||||
pub fn parent_path(&self) -> Option<TypeRef<'a>> {
|
||||
self.tree.graph.neighbors_directed(self.idx, Direction::Incoming).next().map(|i| TypeRef::new(self.tree, i))
|
||||
self.tree
|
||||
.graph
|
||||
.neighbors_directed(self.idx, Direction::Incoming)
|
||||
.next()
|
||||
.map(|i| TypeRef::new(self.tree, i))
|
||||
}
|
||||
|
||||
/// Find the parent **type** based on `parent_type` var, or parent path if unspecified.
|
||||
|
|
@ -237,7 +241,9 @@ impl<'a> TypeRef<'a> {
|
|||
pub fn is_subtype_of(self, parent: &Type) -> bool {
|
||||
let mut current = Some(self);
|
||||
while let Some(ty) = current.take() {
|
||||
if ::std::ptr::eq(ty.get(), parent) { return true }
|
||||
if ::std::ptr::eq(ty.get(), parent) {
|
||||
return true;
|
||||
}
|
||||
current = ty.parent_type();
|
||||
}
|
||||
false
|
||||
|
|
@ -336,7 +342,9 @@ impl ObjectTree {
|
|||
}
|
||||
|
||||
pub fn type_by_path<I>(&self, path: I) -> Option<TypeRef>
|
||||
where I: IntoIterator, I::Item: AsRef<str>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<str>,
|
||||
{
|
||||
let (exact, ty) = self.type_by_path_approx(path);
|
||||
if exact {
|
||||
|
|
@ -347,7 +355,9 @@ impl ObjectTree {
|
|||
}
|
||||
|
||||
pub fn type_by_path_approx<I>(&self, path: I) -> (bool, TypeRef)
|
||||
where I: IntoIterator, I::Item: AsRef<str>
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<str>,
|
||||
{
|
||||
let mut current = NodeIndex::new(0);
|
||||
let mut first = true;
|
||||
|
|
@ -440,7 +450,10 @@ impl ObjectTree {
|
|||
if let Some(&idx) = self.types.get(parent_type) {
|
||||
idx
|
||||
} else {
|
||||
context.register_error(DMError::new(location, format!("bad parent type for {}: {}", path, parent_type)));
|
||||
context.register_error(DMError::new(
|
||||
location,
|
||||
format!("bad parent type for {}: {}", path, parent_type),
|
||||
));
|
||||
NodeIndex::new(0) // on bad parent_type, fall back to the root
|
||||
}
|
||||
};
|
||||
|
|
@ -484,7 +497,12 @@ impl ObjectTree {
|
|||
node
|
||||
}
|
||||
|
||||
fn get_from_path<'a, I: Iterator<Item=&'a str>>(&mut self, location: Location, mut path: I, len: usize) -> Result<(NodeIndex, &'a str), DMError> {
|
||||
fn get_from_path<'a, I: Iterator<Item=&'a str>>(
|
||||
&mut self,
|
||||
location: Location,
|
||||
mut path: I,
|
||||
len: usize,
|
||||
) -> Result<(NodeIndex, &'a str), DMError> {
|
||||
let mut current = NodeIndex::new(0);
|
||||
let mut last = match path.next() {
|
||||
Some(name) => name,
|
||||
|
|
@ -504,14 +522,16 @@ impl ObjectTree {
|
|||
Ok((current, last))
|
||||
}
|
||||
|
||||
fn register_var<'a, I>(&mut self,
|
||||
fn register_var<'a, I>(
|
||||
&mut self,
|
||||
location: Location,
|
||||
parent: NodeIndex,
|
||||
mut prev: &'a str,
|
||||
mut rest: I,
|
||||
comment: DocCollection,
|
||||
) -> Result<Option<&mut TypeVar>, DMError> where
|
||||
I: Iterator<Item=&'a str>
|
||||
) -> Result<Option<&mut TypeVar>, DMError>
|
||||
where
|
||||
I: Iterator<Item=&'a str>,
|
||||
{
|
||||
let (mut is_declaration, mut is_static, mut is_const, mut is_tmp) = (false, false, false, false);
|
||||
|
||||
|
|
@ -519,7 +539,7 @@ impl ObjectTree {
|
|||
is_declaration = true;
|
||||
prev = match rest.next() {
|
||||
Some(name) => name,
|
||||
None => return Ok(None) // var{} block, children will be real vars
|
||||
None => return Ok(None), // var{} block, children will be real vars
|
||||
};
|
||||
while prev == "global" || prev == "static" || prev == "tmp" || prev == "const" {
|
||||
if let Some(name) = rest.next() {
|
||||
|
|
@ -528,11 +548,11 @@ impl ObjectTree {
|
|||
is_tmp |= prev == "tmp";
|
||||
prev = name;
|
||||
} else {
|
||||
return Ok(None) // var/const{} block, children will be real vars
|
||||
return Ok(None); // var/const{} block, children will be real vars
|
||||
}
|
||||
}
|
||||
} else if is_proc_decl(prev) {
|
||||
return Err(DMError::new(location, "proc looks like a var"))
|
||||
return Err(DMError::new(location, "proc looks like a var"));
|
||||
}
|
||||
|
||||
let mut type_path = Vec::new();
|
||||
|
|
@ -566,7 +586,8 @@ impl ObjectTree {
|
|||
})))
|
||||
}
|
||||
|
||||
fn register_proc(&mut self,
|
||||
fn register_proc(
|
||||
&mut self,
|
||||
location: Location,
|
||||
parent: NodeIndex,
|
||||
name: &str,
|
||||
|
|
@ -592,7 +613,8 @@ impl ObjectTree {
|
|||
}
|
||||
|
||||
// an entry which may be anything depending on the path
|
||||
pub fn add_entry<'a, I: Iterator<Item=&'a str>>(&mut self,
|
||||
pub fn add_entry<'a, I: Iterator<Item = &'a str>>(
|
||||
&mut self,
|
||||
location: Location,
|
||||
mut path: I,
|
||||
len: usize,
|
||||
|
|
@ -611,7 +633,8 @@ impl ObjectTree {
|
|||
}
|
||||
|
||||
// an entry which is definitely a var because a value is specified
|
||||
pub fn add_var<'a, I: Iterator<Item=&'a str>>(&mut self,
|
||||
pub fn add_var<'a, I: Iterator<Item = &'a str>>(
|
||||
&mut self,
|
||||
location: Location,
|
||||
mut path: I,
|
||||
len: usize,
|
||||
|
|
@ -629,7 +652,8 @@ impl ObjectTree {
|
|||
}
|
||||
|
||||
// an entry which is definitely a proc because an argument list is specified
|
||||
pub fn add_proc<'a, I: Iterator<Item=&'a str>>(&mut self,
|
||||
pub fn add_proc<'a, I: Iterator<Item = &'a str>>(
|
||||
&mut self,
|
||||
location: Location,
|
||||
mut path: I,
|
||||
len: usize,
|
||||
|
|
@ -641,13 +665,16 @@ impl ObjectTree {
|
|||
is_verb = Some(proc_name == "verb");
|
||||
proc_name = match path.next() {
|
||||
Some(name) => name,
|
||||
None => return Err(DMError::new(location, "proc must have a name"))
|
||||
None => return Err(DMError::new(location, "proc must have a name")),
|
||||
};
|
||||
} else if is_var_decl(proc_name) {
|
||||
return Err(DMError::new(location, "var looks like a proc"))
|
||||
return Err(DMError::new(location, "var looks like a proc"));
|
||||
}
|
||||
if let Some(other) = path.next() {
|
||||
return Err(DMError::new(location, format!("proc name must be a single identifier (spurious {:?})", other)))
|
||||
return Err(DMError::new(
|
||||
location,
|
||||
format!("proc name must be a single identifier (spurious {:?})", other),
|
||||
));
|
||||
}
|
||||
|
||||
self.register_proc(location, parent, proc_name, is_verb, parameters)
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@ use super::docs::*;
|
|||
///
|
||||
/// Compilation failures will return a best-effort parse, and diagnostics will
|
||||
/// be registered with the provided `Context`.
|
||||
pub fn parse<I>(context: &Context, iter: I) -> ObjectTree where
|
||||
I: IntoIterator<Item=LocatedToken>
|
||||
pub fn parse<I>(context: &Context, iter: I) -> ObjectTree
|
||||
where
|
||||
I: IntoIterator<Item=LocatedToken>,
|
||||
{
|
||||
Parser::new(context, iter.into_iter()).parse_object_tree()
|
||||
}
|
||||
|
|
@ -55,7 +56,7 @@ macro_rules! leading {
|
|||
Some(x) => x,
|
||||
None => return Ok(None),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -117,7 +118,7 @@ impl<'a> Iterator for PathStackIter<'a> {
|
|||
|
||||
fn next(&mut self) -> Option<&'a str> {
|
||||
loop {
|
||||
match {self.current}.split_first() {
|
||||
match { self.current }.split_first() {
|
||||
Some((first, rest)) => {
|
||||
self.current = rest;
|
||||
return Some(first);
|
||||
|
|
@ -125,7 +126,7 @@ impl<'a> Iterator for PathStackIter<'a> {
|
|||
None => match self.rest.pop() {
|
||||
Some(c) => self.current = c,
|
||||
None => return None,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -159,8 +160,8 @@ enum Op {
|
|||
impl Op {
|
||||
fn build(self, lhs: Box<Expression>, rhs: Box<Expression>) -> Expression {
|
||||
match self {
|
||||
Op::BinaryOp(op) => Expression::BinaryOp { op: op, lhs: lhs, rhs: rhs },
|
||||
Op::AssignOp(op) => Expression::AssignOp { op: op, lhs: lhs, rhs: rhs },
|
||||
Op::BinaryOp(op) => Expression::BinaryOp { op, lhs, rhs },
|
||||
Op::AssignOp(op) => Expression::AssignOp { op, lhs, rhs },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -354,8 +355,9 @@ impl<'ctx, 'an, I> HasLocation for Parser<'ctx, 'an, I> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
||||
I: Iterator<Item=LocatedToken>
|
||||
impl<'ctx, 'an, I> Parser<'ctx, 'an, I>
|
||||
where
|
||||
I: Iterator<Item=LocatedToken>,
|
||||
{
|
||||
/// Construct a new parser using the given input stream.
|
||||
pub fn new(context: &'ctx Context, input: I) -> Parser<I> {
|
||||
|
|
@ -415,7 +417,12 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
pub fn finalize_object_tree(mut self) -> ObjectTree {
|
||||
let procs_total = self.procs_good + self.procs_bad;
|
||||
if procs_total > 0 {
|
||||
eprintln!("parsed {}/{} proc bodies ({}%)", self.procs_good, procs_total, (self.procs_good * 100 / procs_total));
|
||||
eprintln!(
|
||||
"parsed {}/{} proc bodies ({}%)",
|
||||
self.procs_good,
|
||||
procs_total,
|
||||
(self.procs_good * 100 / procs_total)
|
||||
);
|
||||
}
|
||||
|
||||
let sloppy = self.context.errors().iter().any(|p| p.severity() == Severity::Error);
|
||||
|
|
@ -437,10 +444,10 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
let message = format!("got '{}', expected one of: {}", got, expected);
|
||||
self.put_back(got);
|
||||
self.error(message)
|
||||
},
|
||||
Err(err) => {
|
||||
self.error(format!("i/o error, expected one of: {}", expected)).set_cause(err)
|
||||
}
|
||||
Err(err) => self
|
||||
.error(format!("i/o error, expected one of: {}", expected))
|
||||
.set_cause(err),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -452,7 +459,7 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
match t {
|
||||
Ok(Some(v)) => Ok(v),
|
||||
Ok(None) => self.parse_error(),
|
||||
Err(e) => Err(e)
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -462,15 +469,19 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
break Ok(next);
|
||||
}
|
||||
match self.input.next() {
|
||||
Some(LocatedToken { location, token: Token::DocComment(dc) }) => {
|
||||
match dc.target {
|
||||
DocTarget::EnclosingItem if self.in_docs == 0 => {
|
||||
self.module_docs.entry(location.file).or_default().push((location.line, dc));
|
||||
},
|
||||
DocTarget::EnclosingItem => self.docs_enclosing.push(dc),
|
||||
DocTarget::FollowingItem => self.docs_following.push(dc),
|
||||
Some(LocatedToken {
|
||||
location,
|
||||
token: Token::DocComment(dc),
|
||||
}) => match dc.target {
|
||||
DocTarget::EnclosingItem if self.in_docs == 0 => {
|
||||
self.module_docs
|
||||
.entry(location.file)
|
||||
.or_default()
|
||||
.push((location.line, dc));
|
||||
}
|
||||
}
|
||||
DocTarget::EnclosingItem => self.docs_enclosing.push(dc),
|
||||
DocTarget::FollowingItem => self.docs_following.push(dc),
|
||||
},
|
||||
Some(token) => {
|
||||
self.expected.clear();
|
||||
self.location = token.location;
|
||||
|
|
@ -613,7 +624,9 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
None if !(absolute || spurious_lead) => return Ok(None),
|
||||
None => {
|
||||
slash_loc.column += 1;
|
||||
self.annotate_precise(slash_loc..slash_loc, || Annotation::IncompleteTreePath(absolute, parts.clone()));
|
||||
self.annotate_precise(slash_loc..slash_loc, || {
|
||||
Annotation::IncompleteTreePath(absolute, parts.clone())
|
||||
});
|
||||
self.context.register_error(self.error("path has no effect"));
|
||||
return success((absolute, Vec::new()));
|
||||
}
|
||||
|
|
@ -635,7 +648,9 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
parts.push(i);
|
||||
} else {
|
||||
slash_loc.column += 1;
|
||||
self.annotate_precise(slash_loc..slash_loc, || Annotation::IncompleteTreePath(absolute, parts.clone()));
|
||||
self.annotate_precise(slash_loc..slash_loc, || {
|
||||
Annotation::IncompleteTreePath(absolute, parts.clone())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -659,7 +674,7 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
let (absolute, path) = leading!(self.tree_path());
|
||||
let new_stack = PathStack {
|
||||
parent: if absolute { None } else { Some(&parent) },
|
||||
parts: &path
|
||||
parts: &path,
|
||||
};
|
||||
if absolute && parent.parent.is_some() {
|
||||
self.context.register_error(self.error(format!("nested absolute path: {} inside {}", new_stack, parent))
|
||||
|
|
@ -814,7 +829,12 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
};
|
||||
let (input_type, in_list) = require!(self.input_specifier());
|
||||
success(Parameter {
|
||||
path, name, default, input_type, in_list, location
|
||||
path,
|
||||
name,
|
||||
default,
|
||||
input_type,
|
||||
in_list,
|
||||
location,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -826,9 +846,9 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
};
|
||||
let next = self.next(message)?;
|
||||
if next == terminator || next == Token::Eof {
|
||||
break
|
||||
break;
|
||||
} else if next == Token::Punct(Punctuation::Semicolon) {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
self.put_back(next);
|
||||
require!(self.tree_entry(parent));
|
||||
|
|
@ -838,11 +858,16 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
|
||||
fn tree_block(&mut self, parent: PathStack) -> Status<()> {
|
||||
leading!(self.exact(Token::Punct(Punctuation::LBrace)));
|
||||
Ok(Some(require!(self.tree_entries(parent, Token::Punct(Punctuation::RBrace)))))
|
||||
Ok(Some(require!(
|
||||
self.tree_entries(parent, Token::Punct(Punctuation::RBrace))
|
||||
)))
|
||||
}
|
||||
|
||||
fn root(&mut self) -> Status<()> {
|
||||
let root = PathStack { parent: None, parts: &[] };
|
||||
let root = PathStack {
|
||||
parent: None,
|
||||
parts: &[],
|
||||
};
|
||||
self.tree_entries(root, Token::Eof)
|
||||
}
|
||||
|
||||
|
|
@ -950,7 +975,7 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
arms.push((expr, block));
|
||||
} else {
|
||||
else_arm = Some(require!(self.block(loop_ctx)));
|
||||
break
|
||||
break;
|
||||
}
|
||||
self.skip_phantom_semicolons()?;
|
||||
}
|
||||
|
|
@ -995,14 +1020,26 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
// in-list form ("for list")
|
||||
let (var_type, name) = match init {
|
||||
// this is a really terrible way to do this
|
||||
Statement::Var(VarStatement { var_type, name, value: Some(value) }) => {
|
||||
Statement::Var(VarStatement {
|
||||
var_type,
|
||||
name,
|
||||
value: Some(value),
|
||||
}) => {
|
||||
// for(var/a = 1 to
|
||||
require!(self.exact_ident("to"));
|
||||
let rhs = require!(self.expression());
|
||||
return success(require!(self.for_range(Some(var_type), name, value, rhs)));
|
||||
},
|
||||
Statement::Var(VarStatement { var_type, name, value: None }) => { (Some(var_type), name) },
|
||||
Statement::Expr(Expression::BinaryOp { op: BinaryOp::In, lhs, rhs }) => {
|
||||
}
|
||||
Statement::Var(VarStatement {
|
||||
var_type,
|
||||
name,
|
||||
value: None,
|
||||
}) => (Some(var_type), name),
|
||||
Statement::Expr(Expression::BinaryOp {
|
||||
op: BinaryOp::In,
|
||||
lhs,
|
||||
rhs,
|
||||
}) => {
|
||||
let name = match lhs.into_term() {
|
||||
Some(Term::Ident(name)) => name,
|
||||
_ => return Err(self.error("for-list must start with variable")),
|
||||
|
|
@ -1110,7 +1147,11 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
catch_params = Vec::new();
|
||||
}
|
||||
let catch_block = require!(self.block(loop_ctx));
|
||||
success(Statement::TryCatch { try_block, catch_params, catch_block })
|
||||
success(Statement::TryCatch {
|
||||
try_block,
|
||||
catch_params,
|
||||
catch_block,
|
||||
})
|
||||
// SINGLE-LINE STATEMENTS
|
||||
} else if let Some(()) = self.exact_ident("set")? {
|
||||
let name = require!(self.ident());
|
||||
|
|
@ -1190,7 +1231,7 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
let (_, mut tree_path) = require!(self.tree_path());
|
||||
let name = match tree_path.pop() {
|
||||
Some(name) => name,
|
||||
None => return Err(self.error("'var' must be followed by a name"))
|
||||
None => return Err(self.error("'var' must be followed by a name")),
|
||||
};
|
||||
|
||||
require!(self.var_annotations());
|
||||
|
|
@ -1222,7 +1263,7 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
|
||||
var_stmts.push(VarStatement { var_type, name, value });
|
||||
if in_for || self.exact(Token::Punct(Punctuation::Comma))?.is_none() {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
if var_stmts.len() == 1 {
|
||||
|
|
@ -1248,7 +1289,13 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
|
||||
// for(var/a = 1 to 20
|
||||
// for(var/a in 1 to 20
|
||||
fn for_range(&mut self, var_type: Option<VarType>, name: String, start: Expression, end: Expression) -> Status<Statement> {
|
||||
fn for_range(
|
||||
&mut self,
|
||||
var_type: Option<VarType>,
|
||||
name: String,
|
||||
start: Expression,
|
||||
end: Expression,
|
||||
) -> Status<Statement> {
|
||||
// step 2
|
||||
let step = if let Some(()) = self.exact_ident("step")? {
|
||||
Some(require!(self.expression()))
|
||||
|
|
@ -1321,7 +1368,9 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
parts.push((sep, ident));
|
||||
} else {
|
||||
separator_loc.column += 1;
|
||||
self.annotate_precise(separator_loc..separator_loc, || Annotation::IncompleteTypePath(parts.clone(), sep));
|
||||
self.annotate_precise(separator_loc..separator_loc, || {
|
||||
Annotation::IncompleteTypePath(parts.clone(), sep)
|
||||
});
|
||||
}
|
||||
|
||||
// followed by more path elements, empty ones ignored
|
||||
|
|
@ -1331,7 +1380,9 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
parts.push((sep, ident));
|
||||
} else {
|
||||
separator_loc.column += 1;
|
||||
self.annotate_precise(separator_loc..separator_loc, || Annotation::IncompleteTypePath(parts.clone(), sep));
|
||||
self.annotate_precise(separator_loc..separator_loc, || {
|
||||
Annotation::IncompleteTypePath(parts.clone(), sep)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1479,7 +1530,10 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
Token::Punct(Punctuation::BitNot) => unary_ops.push(UnaryOp::BitNot),
|
||||
Token::Punct(Punctuation::PlusPlus) => unary_ops.push(UnaryOp::PreIncr),
|
||||
Token::Punct(Punctuation::MinusMinus) => unary_ops.push(UnaryOp::PreDecr),
|
||||
other => { self.put_back(other); break }
|
||||
other => {
|
||||
self.put_back(other);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1557,17 +1611,22 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
},
|
||||
|
||||
// term :: 'call' arglist arglist
|
||||
Token::Ident(ref i, _) if i == "call" => {
|
||||
Term::DynamicCall(require!(self.arguments(&[], "call")), require!(self.arguments(&[], "call*")))
|
||||
},
|
||||
Token::Ident(ref i, _) if i == "call" => Term::DynamicCall(
|
||||
require!(self.arguments(&[], "call")),
|
||||
require!(self.arguments(&[], "call*")),
|
||||
),
|
||||
|
||||
// term :: 'input' arglist input_specifier
|
||||
Token::Ident(ref i, _) if i == "input" => match self.arguments(&[], "input")? {
|
||||
Some(args) => {
|
||||
let (input_type, in_list) = require!(self.input_specifier());
|
||||
Term::Input { args, input_type, in_list: in_list.map(Box::new) }
|
||||
Term::Input {
|
||||
args,
|
||||
input_type,
|
||||
in_list: in_list.map(Box::new),
|
||||
}
|
||||
}
|
||||
None => Term::Ident(i.to_owned())
|
||||
None => Term::Ident(i.to_owned()),
|
||||
},
|
||||
|
||||
// term :: 'locate' arglist ('in' expression)?
|
||||
|
|
@ -1587,18 +1646,16 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
};
|
||||
Term::Locate { args, in_list }
|
||||
}
|
||||
None => Term::Ident(i.to_owned())
|
||||
None => Term::Ident(i.to_owned()),
|
||||
},
|
||||
|
||||
// term :: 'pick' pick_arglist
|
||||
Token::Ident(ref i, _) if i == "pick" => match self.pick_arguments()? {
|
||||
Some(args) => Term::Pick(args),
|
||||
None => Term::Ident(i.to_owned())
|
||||
None => Term::Ident(i.to_owned()),
|
||||
},
|
||||
|
||||
Token::Ident(ref i, _) if i == "null" => {
|
||||
Term::Null
|
||||
},
|
||||
Token::Ident(ref i, _) if i == "null" => Term::Null,
|
||||
|
||||
// term :: ident arglist | ident
|
||||
Token::Ident(i, _) => {
|
||||
|
|
@ -1635,7 +1692,9 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
} else {
|
||||
// bare dot
|
||||
dot_loc.column += 1;
|
||||
self.annotate_precise(dot_loc..dot_loc, || Annotation::IncompleteTypePath(Vec::new(), PathOp::Dot));
|
||||
self.annotate_precise(dot_loc..dot_loc, || {
|
||||
Annotation::IncompleteTypePath(Vec::new(), PathOp::Dot)
|
||||
});
|
||||
self.annotate(start, || Annotation::ReturnVal);
|
||||
Term::Ident(".".to_owned())
|
||||
}
|
||||
|
|
@ -1690,14 +1749,14 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
let expr = require!(self.expression());
|
||||
require!(self.exact(Token::Punct(Punctuation::RBracket)));
|
||||
success(Follow::Index(Box::new(expr)))
|
||||
},
|
||||
}
|
||||
|
||||
// follow :: '.' ident arglist?
|
||||
// TODO: only apply these rules if there is no whitespace around the punctuation
|
||||
Token::Punct(Punctuation::Dot) => self.follow_index(IndexKind::Dot, belongs_to),
|
||||
Token::Punct(Punctuation::CloseColon)
|
||||
if !belongs_to.is_empty() || !in_ternary
|
||||
=> self.follow_index(IndexKind::Colon, belongs_to),
|
||||
Token::Punct(Punctuation::CloseColon) if !belongs_to.is_empty() || !in_ternary => {
|
||||
self.follow_index(IndexKind::Colon, belongs_to)
|
||||
},
|
||||
Token::Punct(Punctuation::SafeDot) => self.follow_index(IndexKind::SafeDot, belongs_to),
|
||||
Token::Punct(Punctuation::SafeColon) => self.follow_index(IndexKind::SafeColon, belongs_to),
|
||||
|
||||
|
|
@ -1712,7 +1771,9 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
Some(ident) => ident,
|
||||
None => {
|
||||
index_op_loc.column += kind.len() as u16;
|
||||
self.annotate_precise(index_op_loc..index_op_loc, || Annotation::ScopedMissingIdent(belongs_to.clone()));
|
||||
self.annotate_precise(index_op_loc..index_op_loc, || {
|
||||
Annotation::ScopedMissingIdent(belongs_to.clone())
|
||||
});
|
||||
// register the parse error, but keep going
|
||||
self.context.register_error(self.describe_parse_error());
|
||||
String::new()
|
||||
|
|
@ -1750,13 +1811,18 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
let result = this.expression();
|
||||
this.annotate(arg_start, || Annotation::ProcArgument(arguments.len()));
|
||||
match result {
|
||||
Ok(Some(expr)) => { arguments.push(expr); SUCCESS },
|
||||
Ok(Some(expr)) => {
|
||||
arguments.push(expr);
|
||||
SUCCESS
|
||||
}
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
});
|
||||
let end = self.location; // location of the closing parenthesis
|
||||
self.annotate_precise(start..end, || Annotation::ProcArguments(parents.to_owned(), proc.to_owned(), arguments.len()));
|
||||
self.annotate_precise(start..end, || {
|
||||
Annotation::ProcArguments(parents.to_owned(), proc.to_owned(), arguments.len())
|
||||
});
|
||||
match result {
|
||||
Ok(Some(_)) => success(arguments),
|
||||
Ok(None) => Ok(None),
|
||||
|
|
@ -1766,17 +1832,28 @@ impl<'ctx, 'an, I> Parser<'ctx, 'an, I> where
|
|||
|
||||
fn pick_arguments(&mut self) -> Status<Vec<(Option<Expression>, Expression)>> {
|
||||
leading!(self.exact(Token::Punct(Punctuation::LParen)));
|
||||
success(require!(self.separated(Punctuation::Comma, Punctuation::RParen, None, |this| {
|
||||
let expr = leading!(this.expression());
|
||||
if let Some(()) = this.exact(Token::Punct(Punctuation::Semicolon))? {
|
||||
success((Some(expr), require!(this.expression())))
|
||||
} else {
|
||||
success((None, expr))
|
||||
success(require!(self.separated(
|
||||
Punctuation::Comma,
|
||||
Punctuation::RParen,
|
||||
None,
|
||||
|this| {
|
||||
let expr = leading!(this.expression());
|
||||
if let Some(()) = this.exact(Token::Punct(Punctuation::Semicolon))? {
|
||||
success((Some(expr), require!(this.expression())))
|
||||
} else {
|
||||
success((None, expr))
|
||||
}
|
||||
}
|
||||
})))
|
||||
)))
|
||||
}
|
||||
|
||||
fn separated<R: Clone, F: FnMut(&mut Self) -> Status<R>>(&mut self, sep: Punctuation, terminator: Punctuation, allow_empty: Option<R>, mut f: F) -> Status<Vec<R>> {
|
||||
fn separated<R: Clone, F: FnMut(&mut Self) -> Status<R>>(
|
||||
&mut self,
|
||||
sep: Punctuation,
|
||||
terminator: Punctuation,
|
||||
allow_empty: Option<R>,
|
||||
mut f: F,
|
||||
) -> Status<Vec<R>> {
|
||||
let mut comma_legal = false;
|
||||
let mut elems = Vec::new();
|
||||
loop {
|
||||
|
|
|
|||
|
|
@ -115,12 +115,14 @@ impl DefineMap {
|
|||
return false;
|
||||
}
|
||||
|
||||
self.inner.iter().all(|(key, value)| rhs.inner.get(key).map_or(false, |v| {
|
||||
if value.len() != v.len() {
|
||||
return false;
|
||||
}
|
||||
value.iter().zip(v.iter()).all(|(lhs, rhs)| lhs.1 == rhs.1)
|
||||
}))
|
||||
self.inner.iter().all(|(key, value)| {
|
||||
rhs.inner.get(key).map_or(false, |v| {
|
||||
if value.len() != v.len() {
|
||||
return false;
|
||||
}
|
||||
value.iter().zip(v.iter()).all(|(lhs, rhs)| lhs.1 == rhs.1)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +140,7 @@ enum Include<'ctx> {
|
|||
name: String,
|
||||
location: Location,
|
||||
tokens: VecDeque<Token>,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
impl<'ctx> Include<'ctx> {
|
||||
|
|
@ -210,11 +212,15 @@ impl<'ctx> Iterator for IncludeStack<'ctx> {
|
|||
//Some(Err(e)) => return Some(Err(e)),
|
||||
Some(t) => return Some(t),
|
||||
None => {} // fall through
|
||||
}
|
||||
Some(&mut Include::Expansion { ref mut tokens, location, .. }) => match tokens.pop_front() {
|
||||
},
|
||||
Some(&mut Include::Expansion {
|
||||
ref mut tokens,
|
||||
location,
|
||||
..
|
||||
}) => match tokens.pop_front() {
|
||||
Some(token) => return Some(LocatedToken { location, token }),
|
||||
None => {} // fall through
|
||||
}
|
||||
},
|
||||
None => return None,
|
||||
}
|
||||
self.stack.pop();
|
||||
|
|
@ -234,13 +240,25 @@ struct Ifdef {
|
|||
|
||||
impl Ifdef {
|
||||
fn new(location: Location, active: bool) -> Ifdef {
|
||||
Ifdef { location, active, chain_active: active }
|
||||
Ifdef {
|
||||
location,
|
||||
active,
|
||||
chain_active: active,
|
||||
}
|
||||
}
|
||||
fn else_(self, location: Location) -> Ifdef {
|
||||
Ifdef { location, active: !self.chain_active, chain_active: true }
|
||||
Ifdef {
|
||||
location,
|
||||
active: !self.chain_active,
|
||||
chain_active: true,
|
||||
}
|
||||
}
|
||||
fn else_if(self, location: Location, active: bool) -> Ifdef {
|
||||
Ifdef { location, active: !self.chain_active && active, chain_active: self.chain_active || active }
|
||||
Ifdef {
|
||||
location,
|
||||
active: !self.chain_active && active,
|
||||
chain_active: self.chain_active || active,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -296,9 +314,7 @@ impl<'ctx> Preprocessor<'ctx> {
|
|||
Ok(Preprocessor {
|
||||
context,
|
||||
env_file,
|
||||
include_stack: IncludeStack {
|
||||
stack: vec![include],
|
||||
},
|
||||
include_stack: IncludeStack { stack: vec![include] },
|
||||
history: Default::default(),
|
||||
defines,
|
||||
maps: Default::default(),
|
||||
|
|
@ -462,7 +478,7 @@ impl<'ctx> Preprocessor<'ctx> {
|
|||
self.last_input_loc = tok.location;
|
||||
|
||||
if let Token::Punct(Punctuation::Newline) = tok.token {
|
||||
break
|
||||
break;
|
||||
}
|
||||
|
||||
if let Err(e) = self.real_next(tok.token, true) {
|
||||
|
|
@ -470,8 +486,10 @@ impl<'ctx> Preprocessor<'ctx> {
|
|||
}
|
||||
}
|
||||
|
||||
let mut parser = ::parser::Parser::new(self.context,
|
||||
self.output.drain(..).map(|token| LocatedToken::new(start, token)));
|
||||
let mut parser = ::parser::Parser::new(
|
||||
self.context,
|
||||
self.output.drain(..).map(|token| LocatedToken::new(start, token)),
|
||||
);
|
||||
parser.set_fallback_location(start);
|
||||
let expr = parser.expression();
|
||||
let expr = parser.require(expr)?;
|
||||
|
|
@ -519,10 +537,13 @@ impl<'ctx> Preprocessor<'ctx> {
|
|||
macro_rules! next {
|
||||
() => {
|
||||
match self.inner_next() {
|
||||
Some(x) => { _last_expected_loc = x.location; x.token },
|
||||
None => return Err(self.error("unexpected EOF"))
|
||||
Some(x) => {
|
||||
_last_expected_loc = x.location;
|
||||
x.token
|
||||
}
|
||||
None => return Err(self.error("unexpected EOF")),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! expect_token {
|
||||
(($($i:ident),*) = $p:pat) => {
|
||||
|
|
@ -590,17 +611,27 @@ impl<'ctx> Preprocessor<'ctx> {
|
|||
self.include_stack.top_file_path().parent().unwrap().join(&path),
|
||||
path,
|
||||
].into_iter().rev() {
|
||||
if !candidate.exists() { continue }
|
||||
if !candidate.exists() {
|
||||
continue;
|
||||
}
|
||||
// Double-match is used to let go of the borrow of
|
||||
// `candidate` so it can be used in the second half.
|
||||
enum FileType { DMM, DMF, DMS, DM }
|
||||
enum FileType {
|
||||
DMM,
|
||||
DMF,
|
||||
DMS,
|
||||
DM,
|
||||
}
|
||||
match match candidate.extension().and_then(|s| s.to_str()) {
|
||||
Some("dmm") => FileType::DMM,
|
||||
Some("dmf") => FileType::DMF,
|
||||
Some("dms") => FileType::DMS,
|
||||
Some("dm") => FileType::DM,
|
||||
Some(ext) => {
|
||||
self.context.register_error(DMError::new(self.last_input_loc, format!("unknown extension {:?}", ext)));
|
||||
self.context.register_error(DMError::new(
|
||||
self.last_input_loc,
|
||||
format!("unknown extension {:?}", ext),
|
||||
));
|
||||
return Ok(());
|
||||
}
|
||||
None => {
|
||||
|
|
@ -669,7 +700,7 @@ impl<'ctx> Preprocessor<'ctx> {
|
|||
params.push("__VA_ARGS__".to_owned()); // default
|
||||
variadic = true;
|
||||
}
|
||||
_ => return Err(self.error("malformed macro parameters, expected name"))
|
||||
_ => return Err(self.error("malformed macro parameters, expected name")),
|
||||
}
|
||||
match next!() {
|
||||
Token::Punct(Punctuation::Comma) => {}
|
||||
|
|
@ -681,7 +712,7 @@ impl<'ctx> Preprocessor<'ctx> {
|
|||
_ => return Err(self.error("only the last parameter of a macro may be variadic"))
|
||||
}
|
||||
}
|
||||
_ => return Err(self.error("malformed macro parameters, expected comma"))
|
||||
_ => return Err(self.error("malformed macro parameters, expected comma")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -849,7 +880,7 @@ impl<'ctx> Preprocessor<'ctx> {
|
|||
}
|
||||
}
|
||||
if args.len() != params.len() {
|
||||
return Err(self.error("wrong number of arguments to macro call"))
|
||||
return Err(self.error("wrong number of arguments to macro call"));
|
||||
}
|
||||
|
||||
// paste them into the expansion
|
||||
|
|
@ -871,7 +902,10 @@ impl<'ctx> Preprocessor<'ctx> {
|
|||
let mut arg = args[i].iter().cloned();
|
||||
match arg.next() {
|
||||
Some(Token::Ident(second, ws)) => {
|
||||
expansion.push_back(Token::Ident(format!("{}{}", first, second), ws));
|
||||
expansion.push_back(Token::Ident(
|
||||
format!("{}{}", first, second),
|
||||
ws,
|
||||
));
|
||||
}
|
||||
Some(other) => {
|
||||
expansion.push_back(Token::Ident(first, ws1));
|
||||
|
|
|
|||
|
|
@ -20,12 +20,15 @@ fn floats() {
|
|||
|
||||
#[test]
|
||||
fn nested_interpolation() {
|
||||
assert_eq!(lex(r#""A[B"C"D]E""#), vec![
|
||||
InterpStringBegin("A".into()),
|
||||
Ident("B".into(), false),
|
||||
String("C".into()),
|
||||
Ident("D".into(), false),
|
||||
InterpStringEnd("E".into()),
|
||||
Punct(Newline),
|
||||
]);
|
||||
assert_eq!(
|
||||
lex(r#""A[B"C"D]E""#),
|
||||
vec![
|
||||
InterpStringBegin("A".into()),
|
||||
Ident("B".into(), false),
|
||||
String("C".into()),
|
||||
Ident("D".into(), false),
|
||||
InterpStringEnd("E".into()),
|
||||
Punct(Newline),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,11 @@ fn reconstruct(tokens: &[LocatedToken], iffy: bool) -> String {
|
|||
|
||||
let this_line = &mut reconstructed[line];
|
||||
if this_line.len() > column && !iffy {
|
||||
panic!("column numbers went backwards: line {}, so far {:?}", line + 1, this_line);
|
||||
panic!(
|
||||
"column numbers went backwards: line {}, so far {:?}",
|
||||
line + 1,
|
||||
this_line
|
||||
);
|
||||
}
|
||||
while this_line.len() < column {
|
||||
this_line.push(' ');
|
||||
|
|
|
|||
|
|
@ -31,7 +31,11 @@ fn check_indentor() {
|
|||
let context = Context::default();
|
||||
with_test_dme(&context, |mut preprocessor| {
|
||||
let mut string = Vec::new();
|
||||
pretty_print(&mut string, indents::IndentProcessor::new(&context, &mut preprocessor).map(|t| t.token), true).unwrap();
|
||||
pretty_print(
|
||||
&mut string,
|
||||
indents::IndentProcessor::new(&context, &mut preprocessor).map(|t| t.token),
|
||||
true,
|
||||
).unwrap();
|
||||
context.assert_success();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ fn main() {
|
|||
let out_dir = env::var("OUT_DIR").ok().expect("can't find out_dir");
|
||||
|
||||
if cfg!(target_env="msvc") {
|
||||
if let Err(e) = Command::new("windres").args(&["res/editor.rc", "-o"])
|
||||
if let Err(e) = Command::new("windres")
|
||||
.args(&["res/editor.rc", "-o"])
|
||||
.arg(&format!("{}/editor_rc.lib", out_dir))
|
||||
.status()
|
||||
{
|
||||
|
|
@ -15,16 +16,19 @@ fn main() {
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
if let Err(e) = Command::new("windres").args(&["res/editor.rc", "-o"])
|
||||
if let Err(e) = Command::new("windres")
|
||||
.args(&["res/editor.rc", "-o"])
|
||||
.arg(&format!("{}/editor.rc.o", out_dir))
|
||||
.status()
|
||||
{
|
||||
println!("cargo:warning=`windres` unavailable: {}", e);
|
||||
return;
|
||||
}
|
||||
Command::new("ar").args(&["crus", "libeditor_rc.a", "editor.rc.o"])
|
||||
Command::new("ar")
|
||||
.args(&["crus", "libeditor_rc.a", "editor.rc.o"])
|
||||
.current_dir(Path::new(&out_dir))
|
||||
.status().unwrap();
|
||||
.status()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
println!("cargo:rerun-if-changed=editor.rc");
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ impl Config {
|
|||
pub fn make_recent(&mut self, recent: &Path) {
|
||||
if let Some(first) = self.recent.first() {
|
||||
if first == recent {
|
||||
return // no work to do
|
||||
return; // no work to do
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,10 +63,12 @@ fn save(cfg: &Config, path: &Path) -> io::Result<()> {
|
|||
use serde::Serialize;
|
||||
|
||||
let mut buffer = String::new();
|
||||
cfg.serialize(::toml::ser::Serializer::new(&mut buffer)
|
||||
.pretty_string(true)
|
||||
.pretty_string_literal(false)
|
||||
.pretty_array(true)).unwrap();
|
||||
cfg.serialize(
|
||||
::toml::ser::Serializer::new(&mut buffer)
|
||||
.pretty_string(true)
|
||||
.pretty_string_literal(false)
|
||||
.pretty_array(true),
|
||||
).unwrap();
|
||||
|
||||
if let Some(parent) = path.parent() {
|
||||
fs::create_dir_all(parent)?;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,13 @@ impl IconCache {
|
|||
}
|
||||
|
||||
pub fn get_index(&self, relative_file_path: &Path) -> Option<usize> {
|
||||
let existing = self.lock.read().expect("IconCache poisoned").paths.get(relative_file_path).cloned();
|
||||
let existing = self
|
||||
.lock
|
||||
.read()
|
||||
.expect("IconCache poisoned")
|
||||
.paths
|
||||
.get(relative_file_path)
|
||||
.cloned();
|
||||
// shouldn't be inlined or the lifetime of the lock will be extended
|
||||
match existing {
|
||||
// inner None = failure to load, don't keep trying every time
|
||||
|
|
@ -72,7 +78,7 @@ impl IconCache {
|
|||
lock.paths.insert(relative_file_path.to_owned(), None);
|
||||
None
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +180,7 @@ impl IconFile {
|
|||
}
|
||||
let state_index = match self.metadata.state_names.get(icon_state) {
|
||||
Some(&i) => i,
|
||||
None => return None
|
||||
None => return None,
|
||||
};
|
||||
let state = &self.metadata.states[state_index];
|
||||
|
||||
|
|
@ -193,8 +199,12 @@ impl IconFile {
|
|||
let icon_index = state.offset as u32 + dir_idx;
|
||||
let icon_count = self.width / self.metadata.width;
|
||||
let (icon_x, icon_y) = (icon_index % icon_count, icon_index / icon_count);
|
||||
Some((icon_x * self.metadata.width, icon_y * self.metadata.height,
|
||||
self.metadata.width, self.metadata.height))
|
||||
Some((
|
||||
icon_x * self.metadata.width,
|
||||
icon_y * self.metadata.height,
|
||||
self.metadata.width,
|
||||
self.metadata.height,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,9 +25,7 @@ struct Edit<T, E> {
|
|||
impl<T, E> History<T, E> {
|
||||
pub fn new(desc: String, current: T) -> Self {
|
||||
let mut graph = Graph::default();
|
||||
let idx = graph.add_node(Entry {
|
||||
desc,
|
||||
});
|
||||
let idx = graph.add_node(Entry { desc });
|
||||
History {
|
||||
current,
|
||||
idx,
|
||||
|
|
@ -85,7 +83,10 @@ impl<T, E> History<T, E> {
|
|||
}
|
||||
|
||||
pub fn can_redo(&self) -> bool {
|
||||
self.graph.neighbors_directed(self.idx, Direction::Outgoing).next().is_some()
|
||||
self.graph
|
||||
.neighbors_directed(self.idx, Direction::Outgoing)
|
||||
.next()
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn redo(&mut self, env: &E) {
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ enum MapState {
|
|||
Active {
|
||||
merge_base: Arc<Map>,
|
||||
hist: History,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
struct NewMap {
|
||||
|
|
@ -325,11 +325,18 @@ impl EditorScene {
|
|||
for _ in 0..z {
|
||||
map.rendered.push(None);
|
||||
}
|
||||
MapState::Active { merge_base, hist: History::new("Loaded".to_owned(), val) }
|
||||
MapState::Active {
|
||||
merge_base,
|
||||
hist: History::new("Loaded".to_owned(), val),
|
||||
}
|
||||
} else {
|
||||
MapState::Preparing(merge_base, rx)
|
||||
},
|
||||
MapState::Refreshing { merge_base, mut hist, rx } => if let Ok(val) = rx.try_recv() {
|
||||
MapState::Refreshing {
|
||||
merge_base,
|
||||
mut hist,
|
||||
rx,
|
||||
} => if let Ok(val) = rx.try_recv() {
|
||||
hist.replace_current(val);
|
||||
MapState::Active { merge_base, hist }
|
||||
} else {
|
||||
|
|
@ -376,16 +383,23 @@ impl EditorScene {
|
|||
|
||||
fn run_ui(&mut self, ui: &Ui, renderer: &mut ImRenderer) -> bool {
|
||||
for tool in self.tools.iter_mut() {
|
||||
tool.icon.prepare(self.environment.as_ref(), &mut tools::IconCtx::new(renderer, &mut self.map_renderer));
|
||||
tool.icon.prepare(
|
||||
self.environment.as_ref(),
|
||||
&mut tools::IconCtx::new(renderer, &mut self.map_renderer),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
macro_rules! ctrl_shortcut {
|
||||
($rest:expr) => (im_str!("Ctrl+{}", $rest))
|
||||
($rest:expr) => {
|
||||
im_str!("Ctrl+{}", $rest)
|
||||
};
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
macro_rules! ctrl_shortcut {
|
||||
($rest:expr) => (im_str!("Cmd+{}", $rest))
|
||||
($rest:expr) => {
|
||||
im_str!("Cmd+{}", $rest)
|
||||
};
|
||||
}
|
||||
|
||||
let mut continue_running = true;
|
||||
|
|
@ -580,7 +594,12 @@ impl EditorScene {
|
|||
self.counter = self.counter.wrapping_add(1);
|
||||
let mut i = 0;
|
||||
macro_rules! spinner {
|
||||
() => (SPINNER[(self.counter / 10 + { i += 1; i }) % SPINNER.len()])
|
||||
() => {
|
||||
SPINNER[(self.counter / 10 + {
|
||||
i += 1;
|
||||
i
|
||||
}) % SPINNER.len()]
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(loading) = self.loading_env.as_ref() {
|
||||
|
|
@ -675,17 +694,24 @@ impl EditorScene {
|
|||
for (map_idx, map) in self.maps.iter_mut().enumerate() {
|
||||
let dirty = map.state.hist().map_or(false, |h| h.is_dirty());
|
||||
let title = match map.path {
|
||||
Some(ref path) => format!("{}{}##map_{}", file_name(path), if dirty { " *" } else { "" }, path.display()),
|
||||
Some(ref path) => format!(
|
||||
"{}{}##map_{}",
|
||||
file_name(path),
|
||||
if dirty { " *" } else { "" },
|
||||
path.display()
|
||||
),
|
||||
None => format!("Untitled##{}", map_idx),
|
||||
};
|
||||
if ui.collapsing_header(&ImString::from(title)).default_open(true).build() {
|
||||
if let Some(hist) = map.state.hist() {
|
||||
let world = hist.current();
|
||||
if let Some(dmm) = map.state.base_dmm() {
|
||||
ui.text(im_str!("{:?}; {}-keys: {}",
|
||||
ui.text(im_str!(
|
||||
"{:?}; {}-keys: {}",
|
||||
world.dim_xyz(),
|
||||
dmm.key_length,
|
||||
dmm.dictionary.len()));
|
||||
dmm.dictionary.len()
|
||||
));
|
||||
} else {
|
||||
ui.text(im_str!("{:?}", world.dim_xyz()));
|
||||
}
|
||||
|
|
@ -696,10 +722,12 @@ impl EditorScene {
|
|||
}
|
||||
}
|
||||
} else if let Some(dmm) = map.state.base_dmm() {
|
||||
ui.text(im_str!("{:?}; {}-keys: {}",
|
||||
ui.text(im_str!(
|
||||
"{:?}; {}-keys: {}",
|
||||
dmm.dim_xyz(),
|
||||
dmm.key_length,
|
||||
dmm.dictionary.len()));
|
||||
dmm.dictionary.len()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -797,13 +825,21 @@ impl EditorScene {
|
|||
for _ in 0..new_map.z {
|
||||
rendered.push(None);
|
||||
}
|
||||
let dmm = Map::new(new_map.x as usize, new_map.y as usize, new_map.z as usize,
|
||||
env.turf.clone(), env.area.clone());
|
||||
let dmm = Map::new(
|
||||
new_map.x as usize,
|
||||
new_map.y as usize,
|
||||
new_map.z as usize,
|
||||
env.turf.clone(),
|
||||
env.area.clone(),
|
||||
);
|
||||
let atom_map = map_repr::AtomMap::new(&dmm, &env.icons, &env.objtree);
|
||||
let desc = format!("New {}x{}x{} map", new_map.x, new_map.y, new_map.z);
|
||||
self.maps.push(EditorMap {
|
||||
path: None,
|
||||
state: MapState::Active { merge_base: Arc::new(dmm), hist: History::new(desc, atom_map) },
|
||||
state: MapState::Active {
|
||||
merge_base: Arc::new(dmm),
|
||||
hist: History::new(desc, atom_map),
|
||||
},
|
||||
z_current: 0,
|
||||
center: [new_map.x as f32 * 16.0, new_map.y as f32 * 16.0],
|
||||
rendered,
|
||||
|
|
@ -814,7 +850,11 @@ impl EditorScene {
|
|||
opened = false;
|
||||
}
|
||||
}
|
||||
if opened && !closed { Some(new_map) } else { None }
|
||||
if opened && !closed {
|
||||
Some(new_map)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(map) = self.maps.get_mut(self.map_current) {
|
||||
|
|
@ -828,7 +868,10 @@ impl EditorScene {
|
|||
let mut keep = true;
|
||||
let mut keep2 = true;
|
||||
|
||||
let EditInstance { ref mut inst, ref mut base } = edit;
|
||||
let EditInstance {
|
||||
ref mut inst,
|
||||
ref mut base,
|
||||
} = edit;
|
||||
ui.window(im_str!("{}##{}/{:?}", base.fab.path, uid, inst))
|
||||
.opened(&mut keep)
|
||||
.position(ui.imgui().mouse_pos(), ImGuiCond::Appearing)
|
||||
|
|
@ -883,11 +926,18 @@ impl EditorScene {
|
|||
.always_auto_resize(true)
|
||||
.opened(&mut opened)
|
||||
.build(|| {
|
||||
ui.text(im_str!("maps[{}], map = {}, zoom = {}",
|
||||
ui.text(im_str!(
|
||||
"maps[{}], map = {}, zoom = {}",
|
||||
self.maps.len(),
|
||||
self.map_current, self.map_renderer.zoom));
|
||||
self.map_current,
|
||||
self.map_renderer.zoom
|
||||
));
|
||||
if let Some(env) = self.environment.as_ref() {
|
||||
ui.text(im_str!("types[{}], icons[{}]", env.objtree.graph.node_count(), env.icons.len()));
|
||||
ui.text(im_str!(
|
||||
"types[{}], icons[{}]",
|
||||
env.objtree.graph.node_count(),
|
||||
env.icons.len()
|
||||
));
|
||||
ui.text(im_str!("turf = {}", env.turf));
|
||||
ui.text(im_str!("area = {}", env.area));
|
||||
}
|
||||
|
|
@ -896,7 +946,12 @@ impl EditorScene {
|
|||
if let Some(hist) = map.state.hist() {
|
||||
let current = hist.current();
|
||||
if let Some(level) = current.levels.get(map.z_current) {
|
||||
ui.text(im_str!("draw_calls[{}], pops[{}], atoms[{}]", level.draw_calls.len(), current.pops.len(), level.instances.len()));
|
||||
ui.text(im_str!(
|
||||
"draw_calls[{}], pops[{}], atoms[{}]",
|
||||
level.draw_calls.len(),
|
||||
current.pops.len(),
|
||||
level.instances.len()
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(rendered) = map.rendered.get(map.z_current).and_then(|x| x.as_ref()) {
|
||||
|
|
@ -950,7 +1005,7 @@ impl EditorScene {
|
|||
let ty = ((map.center[1].round() + (cy as f32 - y as f32) / self.map_renderer.zoom) / 32.0).floor() as i32;
|
||||
let (dim_x, dim_y, _) = hist.current().dim_xyz();
|
||||
if tx >= 0 && ty >= 0 && tx < dim_x as i32 && ty < dim_y as i32 {
|
||||
return Some((tx as u32, ty as u32))
|
||||
return Some((tx as u32, ty as u32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1078,21 +1133,22 @@ impl EditorScene {
|
|||
|
||||
Ok(Environment {
|
||||
objtree: Arc::new(objtree),
|
||||
icons: Arc::new(IconCache::new(
|
||||
path.parent().expect("invalid environment file path"))),
|
||||
icons: Arc::new(IconCache::new(path.parent().expect("invalid environment file path"))),
|
||||
turf,
|
||||
area,
|
||||
path,
|
||||
})
|
||||
});
|
||||
self.loading_env = Some(LoadingEnvironment {
|
||||
path: path2,
|
||||
rx,
|
||||
});
|
||||
self.loading_env = Some(LoadingEnvironment { path: path2, rx });
|
||||
}
|
||||
|
||||
fn new_map(&mut self) {
|
||||
self.new_map = Some(NewMap { x: 32, y: 32, z: 1, created: false });
|
||||
self.new_map = Some(NewMap {
|
||||
x: 32,
|
||||
y: 32,
|
||||
z: 1,
|
||||
created: false,
|
||||
});
|
||||
}
|
||||
|
||||
fn open_map(&mut self) {
|
||||
|
|
@ -1297,7 +1353,10 @@ impl EditPrefab {
|
|||
}
|
||||
|
||||
fn show(&mut self, ui: &Ui, env: Option<&Environment>, extra_vars: bool) {
|
||||
let EditPrefab { ref mut filter, ref mut fab } = self;
|
||||
let EditPrefab {
|
||||
ref mut filter,
|
||||
ref mut fab,
|
||||
} = self;
|
||||
|
||||
// find the "best" type by chopping the path if needed
|
||||
let (red_paths, ty) = if let Some(env) = env.as_ref() {
|
||||
|
|
@ -1401,7 +1460,7 @@ fn root_node(ui: &Ui, ty: TypeRef, name: &str) {
|
|||
fn tree_node(ui: &Ui, ty: TypeRef) {
|
||||
let mut children = ty.children();
|
||||
if children.is_empty() {
|
||||
ui.tree_node(im_str!("{}", ty.name)).leaf(true).build(||{});
|
||||
ui.tree_node(im_str!("{}", ty.name)).leaf(true).build(|| {});
|
||||
} else {
|
||||
children.sort_by_key(|t| &t.get().name);
|
||||
ui.tree_node(im_str!("{}", ty.name)).build(|| {
|
||||
|
|
@ -1446,15 +1505,19 @@ fn prepare_tool_icon(
|
|||
) -> tools::ToolIcon {
|
||||
use tools::ToolIcon;
|
||||
match icon {
|
||||
ToolIcon::Dmi { icon, icon_state, tint, dir } => if let Some(env) = environment {
|
||||
ToolIcon::Dmi {
|
||||
icon,
|
||||
icon_state,
|
||||
tint,
|
||||
dir,
|
||||
} => if let Some(env) = environment {
|
||||
if let Some(id) = env.icons.get_index(icon.as_ref()) {
|
||||
let icon = env.icons.get_icon(id);
|
||||
if let Some([u1, v1, u2, v2]) = icon.uv_of(&icon_state, dir) {
|
||||
let tex = map_renderer.icon_textures.retrieve(
|
||||
&mut map_renderer.factory,
|
||||
&env.icons,
|
||||
id,
|
||||
).clone();
|
||||
let tex = map_renderer
|
||||
.icon_textures
|
||||
.retrieve(&mut map_renderer.factory, &env.icons, id)
|
||||
.clone();
|
||||
let samp = map_renderer.sampler.clone();
|
||||
ToolIcon::Loaded {
|
||||
tex: renderer.textures().insert((tex, samp)),
|
||||
|
|
@ -1469,7 +1532,12 @@ fn prepare_tool_icon(
|
|||
ToolIcon::None
|
||||
}
|
||||
} else {
|
||||
ToolIcon::Dmi { icon, icon_state, tint, dir }
|
||||
ToolIcon::Dmi {
|
||||
icon,
|
||||
icon_state,
|
||||
tint,
|
||||
dir,
|
||||
}
|
||||
},
|
||||
ToolIcon::EmbeddedPng { data } => if let Ok(tex) = dmi::texture_from_bytes(&mut map_renderer.factory, data) {
|
||||
let samp = map_renderer.sampler.clone();
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@ impl MapRenderer {
|
|||
|
||||
let sampler = factory.create_sampler(gfx::texture::SamplerInfo::new(
|
||||
gfx::texture::FilterMethod::Scale,
|
||||
gfx::texture::WrapMode::Clamp));
|
||||
gfx::texture::WrapMode::Clamp,
|
||||
));
|
||||
|
||||
MapRenderer {
|
||||
icons: Arc::new(IconCache::new(".".as_ref())),
|
||||
|
|
@ -164,7 +165,16 @@ impl RenderedMap {
|
|||
encoder.update_buffer(&self.ibuf, ibuf_data, 0).expect("update ibuf");
|
||||
}
|
||||
|
||||
pub fn paint(&mut self, parent: &mut MapRenderer, map: &AtomMap, z: u32, center: [f32; 2], factory: &mut Factory, encoder: &mut Encoder, view: &RenderTargetView) {
|
||||
pub fn paint(
|
||||
&mut self,
|
||||
parent: &mut MapRenderer,
|
||||
map: &AtomMap,
|
||||
z: u32,
|
||||
center: [f32; 2],
|
||||
factory: &mut Factory,
|
||||
encoder: &mut Encoder,
|
||||
view: &RenderTargetView,
|
||||
) {
|
||||
// update vertex and index buffers from the map
|
||||
if map.levels[z as usize].buffers_dirty.replace(false) {
|
||||
self.update_buffers(map, z, factory, encoder);
|
||||
|
|
@ -178,9 +188,11 @@ impl RenderedMap {
|
|||
[0.0, 2.0 / y as f32, 0.0, -2.0 * center[1].round() / y as f32],
|
||||
[0.0, 0.0, 1.0, 0.0],
|
||||
[0.0, 0.0, 0.0, 1.0 / parent.zoom],
|
||||
]
|
||||
],
|
||||
};
|
||||
encoder.update_buffer(&parent.transform_buffer, &[transform], 0).expect("update_buffer failed");
|
||||
encoder
|
||||
.update_buffer(&parent.transform_buffer, &[transform], 0)
|
||||
.expect("update_buffer failed");
|
||||
|
||||
let mut start = 0;
|
||||
for call in map.levels[z as usize].draw_calls.iter() {
|
||||
|
|
@ -188,7 +200,9 @@ impl RenderedMap {
|
|||
start += call.len;
|
||||
continue;
|
||||
}
|
||||
let texture = parent.icon_textures.retrieve(factory, &parent.icons, call.texture as usize);
|
||||
let texture = parent
|
||||
.icon_textures
|
||||
.retrieve(factory, &parent.icons, call.texture as usize);
|
||||
let slice = gfx::Slice {
|
||||
start: start,
|
||||
end: start + call.len,
|
||||
|
|
@ -267,8 +281,11 @@ impl RenderPop {
|
|||
|
||||
let color = minimap::color_of(objtree, fab);
|
||||
let color = [
|
||||
color[0] as f32 / 255.0, color[1] as f32 / 255.0,
|
||||
color[2] as f32 / 255.0, color[3] as f32 / 255.0];
|
||||
color[0] as f32 / 255.0,
|
||||
color[1] as f32 / 255.0,
|
||||
color[2] as f32 / 255.0,
|
||||
color[3] as f32 / 255.0,
|
||||
];
|
||||
|
||||
let pixel_x = fab.get_var("pixel_x", objtree).to_int().unwrap_or(0);
|
||||
let pixel_y = fab.get_var("pixel_y", objtree).to_int().unwrap_or(0);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,8 @@ impl AtomMap {
|
|||
let mut coords = HashMap::<(usize, usize, usize), Vec<&Prefab>>::new();
|
||||
for (z, level) in self.levels.iter().enumerate() {
|
||||
for (_, inst) in level.instances.keys_iter() {
|
||||
coords.entry((inst.x as usize, (self.size.1 - 1 - inst.y) as usize, z as usize))
|
||||
coords
|
||||
.entry((inst.x as usize, (self.size.1 - 1 - inst.y) as usize, z as usize))
|
||||
.or_default()
|
||||
.push(&inst.pop);
|
||||
}
|
||||
|
|
@ -181,7 +182,10 @@ impl AtomMap {
|
|||
key
|
||||
} else {
|
||||
let rc = Arc::new(prefab.to_owned());
|
||||
self.pops.insert(rc.clone(), RenderPop::from_prefab(icons, objtree, &prefab).unwrap_or_default());
|
||||
self.pops.insert(
|
||||
rc.clone(),
|
||||
RenderPop::from_prefab(icons, objtree, &prefab).unwrap_or_default(),
|
||||
);
|
||||
rc
|
||||
}
|
||||
}
|
||||
|
|
@ -245,7 +249,9 @@ impl AtomMap {
|
|||
let (draw_call, start) = find_draw_call(draw_calls, pos);
|
||||
|
||||
// extend the draw call or insert a new one
|
||||
let rpop = pops.get(&instances.get_key(new_instance).pop).expect("instance with missing pop");
|
||||
let rpop = pops
|
||||
.get(&instances.get_key(new_instance).pop)
|
||||
.expect("instance with missing pop");
|
||||
if pos == start {
|
||||
// in between two calls
|
||||
if draw_call > 0 && draw_calls[draw_call - 1].can_contain(rpop) {
|
||||
|
|
@ -315,7 +321,10 @@ impl AtomMap {
|
|||
self.add_instance((removed.old.x, removed.old.y, removed.z), pop);
|
||||
}
|
||||
|
||||
pub fn iter_instances<'a>(&'a self, (x, y, z): (u32, u32, u32)) -> impl Iterator<Item=(InstanceId, &'a Prefab)> + 'a {
|
||||
pub fn iter_instances<'a>(
|
||||
&'a self,
|
||||
(x, y, z): (u32, u32, u32),
|
||||
) -> impl Iterator<Item = (InstanceId, &'a Prefab)> + 'a {
|
||||
let level = &self.levels[z as usize];
|
||||
level.sorted_order.iter().rev().filter_map(move |&idx| {
|
||||
let inst = &level.instances.get_key(idx);
|
||||
|
|
@ -382,8 +391,14 @@ impl AtomMap {
|
|||
}
|
||||
|
||||
impl AtomZ {
|
||||
fn prep_instance(&mut self, pops: &mut WeakKeyHashMap<Weak<Prefab>, RenderPop>, (x, y): (u32, u32), prefab: Arc<Prefab>) -> usize {
|
||||
let vertices = pops.get(&prefab)
|
||||
fn prep_instance(
|
||||
&mut self,
|
||||
pops: &mut WeakKeyHashMap<Weak<Prefab>, RenderPop>,
|
||||
(x, y): (u32, u32),
|
||||
prefab: Arc<Prefab>,
|
||||
) -> usize {
|
||||
let vertices = pops
|
||||
.get(&prefab)
|
||||
.map_or_else(|| [Vertex::default(); 4], |rpop| rpop.instance((x, y)));
|
||||
self.instances.push(Instance { x, y, pop: prefab }, vertices)
|
||||
}
|
||||
|
|
@ -479,8 +494,10 @@ impl<K, V> DualPool<K, V> {
|
|||
self.keys.len() - self.freelist.len()
|
||||
}
|
||||
|
||||
pub fn keys_iter<'a>(&'a self) -> impl Iterator<Item=(usize, &'a K)> + 'a {
|
||||
self.keys.iter().enumerate()
|
||||
pub fn keys_iter<'a>(&'a self) -> impl Iterator<Item = (usize, &'a K)> + 'a {
|
||||
self.keys
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(move |(i, _)| !self.freelist.contains(i))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,8 @@ pub fn run(title: String, clear_color: [f32; 4]) -> ::EditorScene {
|
|||
window_hidpi_factor = new_factor;
|
||||
hidpi_factor = window_hidpi_factor.round();
|
||||
frame_size.hidpi_factor = hidpi_factor;
|
||||
frame_size.logical_size = window.get_inner_size()
|
||||
frame_size.logical_size = window
|
||||
.get_inner_size()
|
||||
.unwrap()
|
||||
.to_physical(window_hidpi_factor)
|
||||
.to_logical(hidpi_factor)
|
||||
|
|
@ -162,9 +163,7 @@ pub fn run(title: String, clear_color: [f32; 4]) -> ::EditorScene {
|
|||
Some(Key::X) => imgui.set_key(16, pressed),
|
||||
Some(Key::Y) => imgui.set_key(17, pressed),
|
||||
Some(Key::Z) => imgui.set_key(18, pressed),
|
||||
Some(Key::LControl) | Some(Key::RControl) => {
|
||||
imgui.set_key_ctrl(pressed)
|
||||
}
|
||||
Some(Key::LControl) | Some(Key::RControl) => imgui.set_key_ctrl(pressed),
|
||||
Some(Key::LShift) | Some(Key::RShift) => imgui.set_key_shift(pressed),
|
||||
Some(Key::LAlt) | Some(Key::RAlt) => imgui.set_key_alt(pressed),
|
||||
Some(Key::LWin) | Some(Key::RWin) => imgui.set_key_super(pressed),
|
||||
|
|
@ -217,7 +216,13 @@ pub fn run(title: String, clear_color: [f32; 4]) -> ::EditorScene {
|
|||
.to_logical(hidpi_factor);
|
||||
mouse_state.wheel = diff.y as f32;
|
||||
if !mouse_captured {
|
||||
scene.mouse_wheel(ctrl(&imgui), imgui.key_shift(), imgui.key_alt(), diff.x as f32, diff.y as f32);
|
||||
scene.mouse_wheel(
|
||||
ctrl(&imgui),
|
||||
imgui.key_shift(),
|
||||
imgui.key_alt(),
|
||||
diff.x as f32,
|
||||
diff.y as f32,
|
||||
);
|
||||
}
|
||||
},
|
||||
ReceivedCharacter(c) => imgui.add_input_character(c),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ impl<R: Send + 'static> Task<R> {
|
|||
|
||||
pub fn poll<F: FnMut(Result<R, Err>)>(&self, mut f: F) -> bool {
|
||||
match self.rx.try_recv() {
|
||||
Ok(v) => { f(v); true },
|
||||
Ok(v) => {
|
||||
f(v);
|
||||
true
|
||||
}
|
||||
Err(TryRecvError::Empty) => true,
|
||||
Err(TryRecvError::Disconnected) => false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,14 +43,11 @@ pub enum ToolIcon {
|
|||
|
||||
#[allow(unused_variables)]
|
||||
pub trait ToolBehavior {
|
||||
fn settings(&mut self, ui: &Ui, env: &Environment, ctx: &mut IconCtx) {
|
||||
}
|
||||
fn settings(&mut self, ui: &Ui, env: &Environment, ctx: &mut IconCtx) {}
|
||||
|
||||
fn click(&mut self, hist: &mut History, env: &Environment, loc: (u32, u32, u32)) {
|
||||
}
|
||||
fn click(&mut self, hist: &mut History, env: &Environment, loc: (u32, u32, u32)) {}
|
||||
|
||||
fn pick(&mut self, env: &Environment, prefab: &Prefab) {
|
||||
}
|
||||
fn pick(&mut self, env: &Environment, prefab: &Prefab) {}
|
||||
}
|
||||
|
||||
impl Tool {
|
||||
|
|
@ -73,11 +70,22 @@ impl Tool {
|
|||
}
|
||||
|
||||
fn dmi(self, icon: PathBuf, icon_state: String) -> Self {
|
||||
Tool { icon: ToolIcon::Dmi { icon, icon_state, tint: NO_TINT, dir: dmi::SOUTH }, ..self }
|
||||
Tool {
|
||||
icon: ToolIcon::Dmi {
|
||||
icon,
|
||||
icon_state,
|
||||
tint: NO_TINT,
|
||||
dir: dmi::SOUTH,
|
||||
},
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
fn png(self, data: &'static [u8]) -> Self {
|
||||
Tool { icon: ToolIcon::EmbeddedPng { data }, ..self }
|
||||
Tool {
|
||||
icon: ToolIcon::EmbeddedPng { data },
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
fn build(self, tools: &mut Vec<Tool>) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ enum Visiting {
|
|||
pub struct RangePairIter<'a, K: 'a, V: 'a> {
|
||||
start: Bound<K>,
|
||||
end: Bound<K>,
|
||||
stack: Vec<(&'a Node<K, V>, Visiting)>
|
||||
stack: Vec<(&'a Node<K, V>, Visiting)>,
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V> RangePairIter<'a, K, V> {
|
||||
|
|
@ -73,7 +73,7 @@ impl<'a, K: Ord, V> RangePairIter<'a, K, V> {
|
|||
self.stack.push((node, Visiting::Right));
|
||||
} else {
|
||||
self.stack.push((node, Visiting::Middle(i + 1)));
|
||||
return Some((node, i))
|
||||
return Some((node, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,19 @@ pub struct Node<K, V> {
|
|||
height: u32,
|
||||
pub max: K,
|
||||
pub left: Option<Box<Node<K, V>>>,
|
||||
pub right:Option<Box<Node<K, V>>>,
|
||||
pub right: Option<Box<Node<K, V>>>,
|
||||
}
|
||||
|
||||
impl<K: Ord + Clone, V> Node<K, V> {
|
||||
pub fn new(key: RangeInclusive<K>, data: V) -> Self {
|
||||
Node { max: key.end.clone(), key: key, data: vec![data], height: 1, left: None, right: None }
|
||||
Node {
|
||||
max: key.end.clone(),
|
||||
key: key,
|
||||
data: vec![data],
|
||||
height: 1,
|
||||
left: None,
|
||||
right: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn diff_of_successors_height(&self) -> i32 {
|
||||
|
|
@ -40,13 +47,13 @@ impl<K: Ord + Clone, V> Node<K, V> {
|
|||
}
|
||||
|
||||
///returns the minimal key,value pair within this tree
|
||||
pub fn min_pair(&self) -> (&RangeInclusive<K>,&[V]) {
|
||||
self.left.as_ref().map_or((&self.key,&self.data), |n| n.min_pair())
|
||||
pub fn min_pair(&self) -> (&RangeInclusive<K>, &[V]) {
|
||||
self.left.as_ref().map_or((&self.key, &self.data), |n| n.min_pair())
|
||||
}
|
||||
|
||||
///returns the maximal key,value pair within this tree
|
||||
pub fn max_pair(&self) -> (&RangeInclusive<K>,&[V]) {
|
||||
self.right.as_ref().map_or((&self.key,&self.data), |n| n.max_pair())
|
||||
pub fn max_pair(&self) -> (&RangeInclusive<K>, &[V]) {
|
||||
self.right.as_ref().map_or((&self.key, &self.data), |n| n.max_pair())
|
||||
}
|
||||
|
||||
/// Perform a single right rotation on this (sub) tree
|
||||
|
|
@ -101,7 +108,7 @@ impl<K: Ord + Clone, V> Node<K, V> {
|
|||
2 => self.rotate_left_successor(),
|
||||
1 | 0 | -1 => self,
|
||||
-2 => self.rotate_right_successor(),
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +140,7 @@ impl<K: Ord + Clone, V> Node<K, V> {
|
|||
fn drop_min(mut self: Box<Self>) -> (Option<Box<Self>>, Box<Self>) {
|
||||
match self.left.take() {
|
||||
Some(left) => Node::drop_min_from_left(self, left),
|
||||
None => (self.right.take(), self)
|
||||
None => (self.right.take(), self),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,19 +157,19 @@ impl<K: Ord + Clone, V> Node<K, V> {
|
|||
// empty: None.
|
||||
//
|
||||
//
|
||||
pub fn delete(mut self: Box<Self>, key: RangeInclusive<K>) -> Option<Box<Self>>{
|
||||
pub fn delete(mut self: Box<Self>, key: RangeInclusive<K>) -> Option<Box<Self>> {
|
||||
match self.key.cmp(&key) {
|
||||
Ordering::Equal => return self.delete_root(),
|
||||
Ordering::Less => {
|
||||
if let Some(succ) = self.right.take() {
|
||||
self.right = succ.delete(key);
|
||||
return Some(self.updated_node())
|
||||
return Some(self.updated_node());
|
||||
}
|
||||
},
|
||||
Ordering::Greater => {
|
||||
if let Some(succ) = self.left.take() {
|
||||
self.left = succ.delete(key);
|
||||
return Some(self.updated_node())
|
||||
return Some(self.updated_node());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -175,11 +182,11 @@ impl<K: Ord + Clone, V> Node<K, V> {
|
|||
}
|
||||
|
||||
/// returns a read only reference paie to the data stored under key in the tree given by root
|
||||
pub fn search_pair(&self, key: &RangeInclusive<K>) -> Option<(&RangeInclusive<K>, &[V])>{
|
||||
pub fn search_pair(&self, key: &RangeInclusive<K>) -> Option<(&RangeInclusive<K>, &[V])> {
|
||||
match self.key.cmp(key) {
|
||||
Ordering::Equal => Some((&self.key, &self.data)),
|
||||
Ordering::Less => self.right.as_ref().map_or(None, |succ| succ.search_pair(key)),
|
||||
Ordering::Greater => self.left.as_ref().map_or(None, |succ| succ.search_pair(key))
|
||||
Ordering::Greater => self.left.as_ref().map_or(None, |succ| succ.search_pair(key)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -201,7 +208,7 @@ impl<K: Ord + Clone, V> Node<K, V> {
|
|||
fn insert_in_successor(succ: Option<Box<Self>>, key: RangeInclusive<K>, data: V) -> Option<Box<Self>> {
|
||||
Some(match succ {
|
||||
Some(succ) => succ.insert(key, data),
|
||||
None => Box::new(Node::new(key, data))
|
||||
None => Box::new(Node::new(key, data)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use iterators::RangePairIter;
|
|||
/// An interval tree.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IntervalTree<K, V> {
|
||||
pub(crate) root: Option<Box<Node<K, V>>>
|
||||
pub(crate) root: Option<Box<Node<K, V>>>,
|
||||
}
|
||||
|
||||
impl<K, V> Default for IntervalTree<K, V> {
|
||||
|
|
|
|||
|
|
@ -44,11 +44,16 @@ pub fn item_proc(ty: TypeRef, name: &str, _proc: &TypeProc) -> CompletionItem {
|
|||
CompletionItemKind::Method
|
||||
}),
|
||||
detail: Some(ty.pretty_path().to_owned()),
|
||||
.. Default::default()
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn items_ty<'a>(results: &mut Vec<CompletionItem>, skip: &mut HashSet<(&str, &'a String)>, ty: TypeRef<'a>, query: &str) {
|
||||
pub fn items_ty<'a>(
|
||||
results: &mut Vec<CompletionItem>,
|
||||
skip: &mut HashSet<(&str, &'a String)>,
|
||||
ty: TypeRef<'a>,
|
||||
query: &str,
|
||||
) {
|
||||
// type variables
|
||||
for (name, var) in ty.get().vars.iter() {
|
||||
if !skip.insert(("var", name)) {
|
||||
|
|
@ -82,7 +87,7 @@ pub fn combine_tree_path<'a, I>(iter: &I, mut absolute: bool, mut parts: &'a [St
|
|||
}}
|
||||
// if we're on the right side of a 'var/', start the lookup there
|
||||
if let Some(i) = parts.iter().position(|x| x == "var") {
|
||||
parts = &parts[i+1..];
|
||||
parts = &parts[i + 1..];
|
||||
absolute = true;
|
||||
}
|
||||
// if we're on the right side of a 'list/', start the lookup there
|
||||
|
|
@ -107,7 +112,8 @@ pub fn combine_tree_path<'a, I>(iter: &I, mut absolute: bool, mut parts: &'a [St
|
|||
|
||||
impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
||||
pub fn follow_type_path<'b, I>(&'b self, iter: &I, mut parts: &'b [(PathOp, String)]) -> Option<TypePathResult<'b>>
|
||||
where I: Iterator<Item=(Span, &'a Annotation)> + Clone
|
||||
where
|
||||
I: Iterator<Item = (Span, &'a Annotation)> + Clone,
|
||||
{
|
||||
// cut off the part of the path we haven't selected
|
||||
if_annotation! { Annotation::InSequence(idx) in iter; {
|
||||
|
|
@ -121,17 +127,19 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
|
||||
// use the first path op to select the starting type of the lookup
|
||||
if parts.is_empty() {
|
||||
return Some(TypePathResult { ty: self.objtree.root(), decl: None, proc: None });
|
||||
return Some(TypePathResult {
|
||||
ty: self.objtree.root(),
|
||||
decl: None,
|
||||
proc: None,
|
||||
});
|
||||
}
|
||||
let mut ty = match parts[0].0 {
|
||||
PathOp::Colon => return None, // never finds anything, apparently?
|
||||
PathOp::Slash => self.objtree.root(),
|
||||
PathOp::Dot => {
|
||||
match self.find_type_context(iter) {
|
||||
(Some(base), _) => base,
|
||||
(None, _) => self.objtree.root(),
|
||||
}
|
||||
}
|
||||
PathOp::Dot => match self.find_type_context(iter) {
|
||||
(Some(base), _) => base,
|
||||
(None, _) => self.objtree.root(),
|
||||
},
|
||||
};
|
||||
|
||||
// follow the path ops until we hit 'proc' or 'verb'
|
||||
|
|
@ -236,13 +244,24 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn path_completions<'b, I>(&'b self, results: &mut Vec<CompletionItem>, iter: &I, parts: &'b [(PathOp, String)], _last_op: PathOp, query: &str)
|
||||
where I: Iterator<Item=(Span, &'b Annotation)> + Clone
|
||||
pub fn path_completions<'b, I>(
|
||||
&'b self,
|
||||
results: &mut Vec<CompletionItem>,
|
||||
iter: &I,
|
||||
parts: &'b [(PathOp, String)],
|
||||
_last_op: PathOp,
|
||||
query: &str,
|
||||
) where
|
||||
I: Iterator<Item = (Span, &'b Annotation)> + Clone,
|
||||
{
|
||||
// TODO: take last_op into account
|
||||
match self.follow_type_path(iter, parts) {
|
||||
// '/datum/<complete types>'
|
||||
Some(TypePathResult { ty, decl: None, proc: None }) => {
|
||||
Some(TypePathResult {
|
||||
ty,
|
||||
decl: None,
|
||||
proc: None,
|
||||
}) => {
|
||||
// path keywords
|
||||
for &name in ["proc", "verb"].iter() {
|
||||
if contains(name, query) {
|
||||
|
|
@ -267,7 +286,11 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
},
|
||||
// '/datum/proc/<complete procs>'
|
||||
// TODO: take the path op into acocunt (`/proc` vs `.proc`)
|
||||
Some(TypePathResult { ty, decl: Some(decl), proc: None }) => {
|
||||
Some(TypePathResult {
|
||||
ty,
|
||||
decl: Some(decl),
|
||||
proc: None,
|
||||
}) => {
|
||||
let mut next = Some(ty);
|
||||
let mut skip = HashSet::new();
|
||||
while let Some(ty) = next {
|
||||
|
|
@ -279,10 +302,10 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
// declarations only
|
||||
let mut proc_decl = match proc.declaration.as_ref() {
|
||||
Some(decl) => decl,
|
||||
None => continue
|
||||
None => continue,
|
||||
};
|
||||
if proc_decl.is_verb != (decl == "verb") {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
if contains(name, query) {
|
||||
results.push(item_proc(ty, name, proc));
|
||||
|
|
@ -296,7 +319,8 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
}
|
||||
|
||||
pub fn unscoped_completions<'b, I>(&'b self, results: &mut Vec<CompletionItem>, iter: &I, query: &str)
|
||||
where I: Iterator<Item=(Span, &'b Annotation)> + Clone
|
||||
where
|
||||
I: Iterator<Item = (Span, &'b Annotation)> + Clone,
|
||||
{
|
||||
let (ty, proc_name) = self.find_type_context(iter);
|
||||
|
||||
|
|
@ -368,8 +392,14 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn scoped_completions<'b, I>(&'b self, results: &mut Vec<CompletionItem>, iter: &I, priors: &[String], query: &str)
|
||||
where I: Iterator<Item=(Span, &'b Annotation)> + Clone
|
||||
pub fn scoped_completions<'b, I>(
|
||||
&'b self,
|
||||
results: &mut Vec<CompletionItem>,
|
||||
iter: &I,
|
||||
priors: &[String],
|
||||
query: &str,
|
||||
) where
|
||||
I: Iterator<Item = (Span, &'b Annotation)> + Clone,
|
||||
{
|
||||
let mut next = self.find_scoped_type(iter, priors);
|
||||
let mut skip = HashSet::new();
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ impl DocumentStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn change(&mut self,
|
||||
pub fn change(
|
||||
&mut self,
|
||||
doc_id: VersionedTextDocumentIdentifier,
|
||||
changes: Vec<TextDocumentContentChangeEvent>,
|
||||
) -> Result<PathBuf, jsonrpc::Error> {
|
||||
|
|
@ -48,7 +49,7 @@ impl DocumentStore {
|
|||
// the client and the file is not open in the editor (the server has
|
||||
// not received an open notification before) the server can send `null`
|
||||
// to indicate that the version is known and the content on disk is the
|
||||
// truth (as speced with document content ownership)."
|
||||
// truth (as speced with document content ownership)."
|
||||
let new_version = match doc_id.version {
|
||||
Some(version) => version,
|
||||
None => return Err(invalid_request("don't know how to deal with this")),
|
||||
|
|
@ -103,7 +104,10 @@ struct Document {
|
|||
|
||||
impl Document {
|
||||
fn new(version: u64, text: String) -> Document {
|
||||
Document { version, text: Rc::new(text) }
|
||||
Document {
|
||||
version,
|
||||
text: Rc::new(text),
|
||||
}
|
||||
}
|
||||
|
||||
fn change(&mut self, change: TextDocumentContentChangeEvent) -> Result<(), jsonrpc::Error> {
|
||||
|
|
@ -118,7 +122,7 @@ impl Document {
|
|||
};
|
||||
|
||||
let start_pos = total_offset(&self.text, range.start.line, range.start.character)?;
|
||||
Rc::make_mut(&mut self.text).replace_range(start_pos .. start_pos + range_length as usize, &change.text);
|
||||
Rc::make_mut(&mut self.text).replace_range(start_pos..start_pos + range_length as usize, &change.text);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -150,7 +154,7 @@ pub fn find_word(text: &str, offset: usize) -> &str {
|
|||
start_next -= 1;
|
||||
}
|
||||
if !text[start_next..start].chars().next().map_or(false, is_ident) {
|
||||
break
|
||||
break;
|
||||
}
|
||||
start = start_next;
|
||||
}
|
||||
|
|
@ -163,7 +167,7 @@ pub fn find_word(text: &str, offset: usize) -> &str {
|
|||
end_next += 1;
|
||||
}
|
||||
if !text[end..end_next].chars().next().map_or(false, is_ident) {
|
||||
break
|
||||
break;
|
||||
}
|
||||
end = end_next;
|
||||
}
|
||||
|
|
@ -212,5 +216,7 @@ impl BufRead for Cursor {
|
|||
let amt = ::std::cmp::min(self.pos, self.inner.as_ref().len() as u64);
|
||||
Ok(&self.inner.as_bytes()[(amt as usize)..])
|
||||
}
|
||||
fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
|
||||
fn consume(&mut self, amt: usize) {
|
||||
self.pos += amt as u64;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,25 +20,25 @@ impl RequestRead for StdIo {
|
|||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
eprintln!("{:?}", e);
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// read the content-length
|
||||
let mut buffer = String::new();
|
||||
check!(io::stdin().read_line(&mut buffer));
|
||||
if buffer.is_empty() {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
let size = {
|
||||
let parts: Vec<&str> = buffer.split(' ').collect();
|
||||
if parts.len() != 2 {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
if !parts[0].eq_ignore_ascii_case("content-length:") {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
check!(usize::from_str_radix(parts[1].trim(), 10))
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,7 +41,10 @@ use dm::objtree::TypeRef;
|
|||
fn main() {
|
||||
std::env::set_var("RUST_BACKTRACE", "1");
|
||||
|
||||
eprintln!("dm-langserver {} Copyright (C) 2017-2018 Tad Hardesty", env!("CARGO_PKG_VERSION"));
|
||||
eprintln!(
|
||||
"dm-langserver {} Copyright (C) 2017-2018 Tad Hardesty",
|
||||
env!("CARGO_PKG_VERSION")
|
||||
);
|
||||
eprintln!("This program comes with ABSOLUTELY NO WARRANTY. This is free software,");
|
||||
eprintln!("and you are welcome to redistribute it under the conditions of the GNU");
|
||||
eprintln!("General Public License version 3.");
|
||||
|
|
@ -110,7 +113,8 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
// ------------------------------------------------------------------------
|
||||
// General input and output utilities
|
||||
|
||||
fn issue_notification<T>(&mut self, params: T::Params) where
|
||||
fn issue_notification<T>(&mut self, params: T::Params)
|
||||
where
|
||||
T: langserver::notification::Notification,
|
||||
T::Params: serde::Serialize,
|
||||
{
|
||||
|
|
@ -198,7 +202,7 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
message: err.description().to_owned(),
|
||||
.. Default::default()
|
||||
}],
|
||||
}
|
||||
},
|
||||
);
|
||||
eprintln!("{:?}", err);
|
||||
return Ok(());
|
||||
|
|
@ -210,7 +214,11 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
self.preprocessor = Some(pp);
|
||||
self.issue_notification::<extras::WindowStatus>(Default::default());
|
||||
let elapsed = start.elapsed();
|
||||
eprintln!("parsed in {}.{:03}s", elapsed.as_secs(), elapsed.subsec_nanos() / 1_000_000);
|
||||
eprintln!(
|
||||
"parsed in {}.{:03}s",
|
||||
elapsed.as_secs(),
|
||||
elapsed.subsec_nanos() / 1_000_000
|
||||
);
|
||||
|
||||
// initial diagnostics pump
|
||||
let mut map: HashMap<_, Vec<_>> = HashMap::new();
|
||||
|
|
@ -240,7 +248,7 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
langserver::PublishDiagnosticsParams {
|
||||
uri: path_to_url(joined_path)?,
|
||||
diagnostics,
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -279,7 +287,8 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
}
|
||||
|
||||
fn find_type_context<'b, I, Ign>(&self, iter: &I) -> (Option<TypeRef>, Option<(&'b str, usize)>)
|
||||
where I: Iterator<Item=(Ign, &'b Annotation)> + Clone
|
||||
where
|
||||
I: Iterator<Item = (Ign, &'b Annotation)> + Clone,
|
||||
{
|
||||
let mut found = None;
|
||||
let mut proc_name = None;
|
||||
|
|
@ -314,14 +323,24 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
(found, proc_name)
|
||||
}
|
||||
|
||||
fn find_unscoped_var<'b, I>(&'b self, iter: &I, ty: Option<TypeRef<'b>>, proc_name: Option<(&'b str, usize)>, var_name: &str) -> UnscopedVar<'b>
|
||||
where I: Iterator<Item=(Span, &'b Annotation)> + Clone
|
||||
fn find_unscoped_var<'b, I>(
|
||||
&'b self,
|
||||
iter: &I,
|
||||
ty: Option<TypeRef<'b>>,
|
||||
proc_name: Option<(&'b str, usize)>,
|
||||
var_name: &str,
|
||||
) -> UnscopedVar<'b>
|
||||
where
|
||||
I: Iterator<Item = (Span, &'b Annotation)> + Clone,
|
||||
{
|
||||
// local variables
|
||||
for (span, annotation) in iter.clone() {
|
||||
if let Annotation::LocalVarScope(var_type, name) = annotation {
|
||||
if name == var_name {
|
||||
return UnscopedVar::Local { loc: span.start, var_type }
|
||||
return UnscopedVar::Local {
|
||||
loc: span.start,
|
||||
var_type,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -386,7 +405,7 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
next = self.objtree.type_by_path(&decl.var_type.type_path);
|
||||
}
|
||||
} else {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
next
|
||||
|
|
@ -402,17 +421,15 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
let mut outputs: Vec<Output> = match serde_json::from_str(&message) {
|
||||
Ok(Request::Single(call)) => self.handle_call(call).into_iter().collect(),
|
||||
Ok(Request::Batch(calls)) => calls.into_iter().flat_map(|call| self.handle_call(call)).collect(),
|
||||
Err(decode_error) => {
|
||||
vec![Output::Failure(jsonrpc::Failure {
|
||||
jsonrpc: VERSION,
|
||||
error: jsonrpc::Error {
|
||||
code: jsonrpc::ErrorCode::ParseError,
|
||||
message: decode_error.to_string(),
|
||||
data: None,
|
||||
},
|
||||
id: jsonrpc::Id::Null,
|
||||
})]
|
||||
}
|
||||
Err(decode_error) => vec![Output::Failure(jsonrpc::Failure {
|
||||
jsonrpc: VERSION,
|
||||
error: jsonrpc::Error {
|
||||
code: jsonrpc::ErrorCode::ParseError,
|
||||
message: decode_error.to_string(),
|
||||
data: None,
|
||||
},
|
||||
id: jsonrpc::Id::Null,
|
||||
})],
|
||||
};
|
||||
|
||||
let response = match outputs.len() {
|
||||
|
|
@ -427,9 +444,7 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
|
|||
|
||||
fn handle_call(&mut self, call: Call) -> Option<Output> {
|
||||
match call {
|
||||
Call::Invalid(id) => {
|
||||
Some(Output::invalid_request(id, VERSION))
|
||||
},
|
||||
Call::Invalid(id) => Some(Output::invalid_request(id, VERSION)),
|
||||
Call::MethodCall(method_call) => {
|
||||
let id = method_call.id.clone();
|
||||
Some(Output::from(self.handle_method_call(method_call), id, VERSION))
|
||||
|
|
@ -1003,7 +1018,7 @@ fn value_to_params(value: serde_json::Value) -> jsonrpc::Params {
|
|||
serde_json::Value::Null => jsonrpc::Params::None,
|
||||
serde_json::Value::Array(x) => jsonrpc::Params::Array(x),
|
||||
serde_json::Value::Object(x) => jsonrpc::Params::Map(x),
|
||||
_ => panic!("bad value to params conversion")
|
||||
_ => panic!("bad value to params conversion"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,20 +14,20 @@ impl Query {
|
|||
/// Parse a symbol query.
|
||||
pub fn parse(query: &str) -> Option<Query> {
|
||||
if !any_alphanumeric(query) {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
Some(if query.starts_with("#") {
|
||||
Query::Define(query[1..].to_lowercase())
|
||||
} else if query.starts_with("var/") {
|
||||
let query = &query["var/".len()..];
|
||||
if !any_alphanumeric(query) {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
Query::Var(query.to_lowercase())
|
||||
} else if query.starts_with("proc/") {
|
||||
let query = &query["proc/".len()..];
|
||||
if !any_alphanumeric(query) {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
Query::Proc(query.to_lowercase())
|
||||
} else if query.contains("/") {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ impl IconFile {
|
|||
pub fn rect_of(&self, icon_state: &str, dir: i32) -> Option<Rect> {
|
||||
let state_index = match self.metadata.state_names.get(icon_state) {
|
||||
Some(&i) => i,
|
||||
None => return None
|
||||
None => return None,
|
||||
};
|
||||
let state = &self.metadata.states[state_index];
|
||||
|
||||
|
|
@ -83,12 +83,15 @@ impl IconFile {
|
|||
let icon_index = state.offset as u32 + dir_idx;
|
||||
let icon_count = self.image.width / self.metadata.width;
|
||||
let (icon_x, icon_y) = (icon_index % icon_count, icon_index / icon_count);
|
||||
Some((icon_x * self.metadata.width, icon_y * self.metadata.height,
|
||||
self.metadata.width, self.metadata.height))
|
||||
Some((
|
||||
icon_x * self.metadata.width,
|
||||
icon_y * self.metadata.height,
|
||||
self.metadata.width,
|
||||
self.metadata.height,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Image manipulation
|
||||
|
||||
|
|
@ -163,19 +166,26 @@ impl Image {
|
|||
use ndarray::Axis;
|
||||
|
||||
let mut destination = self.data.slice_mut(s![
|
||||
pos.1 as isize .. (pos.1 + crop.3) as isize,
|
||||
pos.0 as isize .. (pos.0 + crop.2) as isize,
|
||||
..]);
|
||||
pos.1 as isize..(pos.1 + crop.3) as isize,
|
||||
pos.0 as isize..(pos.0 + crop.2) as isize,
|
||||
..
|
||||
]);
|
||||
let source = other.data.slice(s![
|
||||
crop.1 as isize .. (crop.1 + crop.3) as isize,
|
||||
crop.0 as isize .. (crop.0 + crop.2) as isize,
|
||||
..]);
|
||||
crop.1 as isize..(crop.1 + crop.3) as isize,
|
||||
crop.0 as isize..(crop.0 + crop.2) as isize,
|
||||
..
|
||||
]);
|
||||
|
||||
// loop over each [r, g, b, a] available in the relevant area
|
||||
for (mut dest, orig_src) in destination.lanes_mut(Axis(2)).into_iter().zip(source.lanes(Axis(2))) {
|
||||
macro_rules! tint { ($i:expr) => {
|
||||
mul255(*orig_src.get($i).unwrap_or(&255), *color.get($i).unwrap_or(&255))
|
||||
}}
|
||||
macro_rules! tint {
|
||||
($i:expr) => {
|
||||
mul255(
|
||||
*orig_src.get($i).unwrap_or(&255),
|
||||
*color.get($i).unwrap_or(&255),
|
||||
)
|
||||
};
|
||||
}
|
||||
let src = [tint!(0), tint!(1), tint!(2), tint!(3)];
|
||||
|
||||
// out_A = src_A + dst_A (1 - src_A)
|
||||
|
|
@ -183,7 +193,9 @@ impl Image {
|
|||
let out_a = src[3] + mul255(dest[3], 255 - src[3]);
|
||||
if out_a != 0 {
|
||||
for i in 0..3 {
|
||||
dest[i] = ((src[i] as u32 * src[3] as u32 + dest[i] as u32 * dest[3] as u32 * (255 - src[3] as u32) / 255) / out_a as u32) as u8;
|
||||
dest[i] = ((src[i] as u32 * src[3] as u32
|
||||
+ dest[i] as u32 * dest[3] as u32 * (255 - src[3] as u32) / 255)
|
||||
/ out_a as u32) as u8;
|
||||
}
|
||||
} else {
|
||||
for i in 0..3 {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,10 @@ impl Map {
|
|||
|
||||
impl Prefab {
|
||||
pub fn from_path<S: Into<String>>(path: S) -> Prefab {
|
||||
Prefab { path: path.into(), vars: Default::default() }
|
||||
Prefab {
|
||||
path: path.into(),
|
||||
vars: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,11 +276,11 @@ fn parse_map(map: &mut Map, f: File) -> Result<(), DMError> {
|
|||
if ch == b'\n' || ch == b'\r' {
|
||||
in_comment_line = false;
|
||||
comment_trigger = false;
|
||||
continue
|
||||
continue;
|
||||
} else if in_comment_line {
|
||||
continue
|
||||
continue;
|
||||
} else if ch == b'\t' {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if ch == b'/' && !in_quote_block {
|
||||
|
|
@ -319,19 +322,23 @@ fn parse_map(map: &mut Map, f: File) -> Result<(), DMError> {
|
|||
} else if ch == b'=' && curr_var.is_empty() {
|
||||
curr_var = take(&mut curr_datum);
|
||||
let mut length = curr_var.len();
|
||||
while length > 0 && (curr_var[length-1] as char).is_whitespace() {
|
||||
while length > 0 && (curr_var[length - 1] as char).is_whitespace() {
|
||||
length -= 1;
|
||||
}
|
||||
curr_var.truncate(length);
|
||||
skip_whitespace = true;
|
||||
} else if ch == b';' {
|
||||
curr_prefab.vars.insert(from_latin1(take(&mut curr_var)),
|
||||
parse_constant(chars.location(), take(&mut curr_datum))?);
|
||||
curr_prefab.vars.insert(
|
||||
from_latin1(take(&mut curr_var)),
|
||||
parse_constant(chars.location(), take(&mut curr_datum))?,
|
||||
);
|
||||
skip_whitespace = true;
|
||||
} else if ch == b'}' {
|
||||
if !curr_var.is_empty() {
|
||||
curr_prefab.vars.insert(from_latin1(take(&mut curr_var)),
|
||||
parse_constant(chars.location(), take(&mut curr_datum))?);
|
||||
curr_prefab.vars.insert(
|
||||
from_latin1(take(&mut curr_var)),
|
||||
parse_constant(chars.location(), take(&mut curr_datum))?,
|
||||
);
|
||||
}
|
||||
in_varedit_block = false;
|
||||
} else {
|
||||
|
|
@ -387,7 +394,9 @@ fn parse_map(map: &mut Map, f: File) -> Result<(), DMError> {
|
|||
// grid
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum Coord {
|
||||
X, Y, Z
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
}
|
||||
|
||||
let mut grid = BTreeMap::new();
|
||||
|
|
@ -426,7 +435,7 @@ fn parse_map(map: &mut Map, f: File) -> Result<(), DMError> {
|
|||
} else {
|
||||
match (ch as char).to_digit(10) {
|
||||
Some(x) => curr_num = 10 * curr_num + x as usize,
|
||||
None => return Err(DMError::new(Location::default(), "bad digit in map coordinate"))
|
||||
None => return Err(DMError::new(Location::default(), "bad digit in map coordinate")),
|
||||
}
|
||||
}
|
||||
} else if in_map_string {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,8 @@ pub fn check(
|
|||
}
|
||||
|
||||
pub fn retain_mut<T, F>(v: &mut Vec<T>, mut f: F)
|
||||
where F: FnMut(&mut T) -> bool
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
let len = v.len();
|
||||
let mut del = 0;
|
||||
|
|
|
|||
|
|
@ -25,11 +25,14 @@ pub struct Context<'a> {
|
|||
pub render_passes: &'a [Box<RenderPass>],
|
||||
}
|
||||
|
||||
pub fn generate(
|
||||
ctx: Context,
|
||||
icon_cache: &IconCache,
|
||||
) -> Result<Image, ()> {
|
||||
let Context { objtree, map, grid, render_passes, .. } = ctx;
|
||||
pub fn generate(ctx: Context, icon_cache: &IconCache) -> Result<Image, ()> {
|
||||
let Context {
|
||||
objtree,
|
||||
map,
|
||||
grid,
|
||||
render_passes,
|
||||
..
|
||||
} = ctx;
|
||||
|
||||
// transform min/max from bottom-left-based to top-left-based
|
||||
// probably doesn't belong here
|
||||
|
|
@ -42,16 +45,26 @@ pub fn generate(
|
|||
let mut overlays = Vec::new();
|
||||
|
||||
for (y, row) in grid.axis_iter(Axis(0)).enumerate() {
|
||||
if y < min_y || y > max_y { continue }
|
||||
if y < min_y || y > max_y {
|
||||
continue;
|
||||
}
|
||||
for (x, e) in row.iter().enumerate() {
|
||||
if x < ctx.min.0 || x > ctx.max.0 { continue }
|
||||
if x < ctx.min.0 || x > ctx.max.0 {
|
||||
continue;
|
||||
}
|
||||
for mut atom in get_atom_list(objtree, &map.dictionary[e], (x as u32, y as u32), render_passes) {
|
||||
// icons which differ from their map states
|
||||
let p = &atom.type_.path;
|
||||
if p == "/obj/structure/table/wood/fancy/black" {
|
||||
atom.set_var("icon", Constant::Resource("icons/obj/smooth_structures/fancy_table_black.dmi".into()));
|
||||
atom.set_var(
|
||||
"icon",
|
||||
Constant::Resource("icons/obj/smooth_structures/fancy_table_black.dmi".into()),
|
||||
);
|
||||
} else if p == "/obj/structure/table/wood/fancy" {
|
||||
atom.set_var("icon", Constant::Resource("icons/obj/smooth_structures/fancy_table.dmi".into()));
|
||||
atom.set_var(
|
||||
"icon",
|
||||
Constant::Resource("icons/obj/smooth_structures/fancy_table.dmi".into()),
|
||||
);
|
||||
} else if subtype(p, "/turf/closed/mineral/") {
|
||||
atom.set_var("pixel_x", Constant::Int(-4));
|
||||
atom.set_var("pixel_y", Constant::Int(-4));
|
||||
|
|
@ -67,18 +80,24 @@ pub fn generate(
|
|||
let mut copy = atom.clone();
|
||||
copy.set_var("icon_state", Constant::string($icon));
|
||||
overlays.push(copy);
|
||||
}}
|
||||
}};
|
||||
}
|
||||
if subtype(p, "/obj/structure/closet/") {
|
||||
// closet doors
|
||||
if atom.get_var("opened", objtree).to_bool() {
|
||||
let var = if atom.get_var("icon_door_override", objtree).to_bool() { "icon_door" } else { "icon_state" };
|
||||
let var = if atom.get_var("icon_door_override", objtree).to_bool() {
|
||||
"icon_door"
|
||||
} else {
|
||||
"icon_state"
|
||||
};
|
||||
if let &Constant::String(ref door) = atom.get_var(var, objtree) {
|
||||
add_overlay!(format!("{}_open", door));
|
||||
}
|
||||
} else {
|
||||
if let &Constant::String(ref door) = atom.get_var_notnull("icon_door", objtree)
|
||||
.unwrap_or_else(|| atom.get_var("icon_state", objtree)) {
|
||||
if let &Constant::String(ref door) = atom
|
||||
.get_var_notnull("icon_door", objtree)
|
||||
.unwrap_or_else(|| atom.get_var("icon_state", objtree))
|
||||
{
|
||||
add_overlay!(format!("{}_door", door));
|
||||
}
|
||||
if atom.get_var("welded", objtree).to_bool() {
|
||||
|
|
@ -122,7 +141,7 @@ pub fn generate(
|
|||
"scrub_map" => "scrub_off",
|
||||
"scrub_map_on" => "scrub_on",
|
||||
_ => "",
|
||||
}
|
||||
},
|
||||
_ => "",
|
||||
};
|
||||
if !aboveground.is_empty() {
|
||||
|
|
@ -175,7 +194,7 @@ pub fn generate(
|
|||
&Constant::Resource(ref path) | &Constant::String(ref path) => path,
|
||||
_ => {
|
||||
println!("no icon: {}", atom.type_.path);
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let icon_state = match atom.get_var("icon_state", objtree) {
|
||||
|
|
@ -196,7 +215,7 @@ pub fn generate(
|
|||
icon_file.metadata.height as i32;
|
||||
let mut loc = (
|
||||
((atom.loc.0 - ctx.min.0 as u32) * TILE_SIZE) as i32 + pixel_x,
|
||||
((atom.loc.1 + 1 - min_y as u32) * TILE_SIZE) as i32 - pixel_y
|
||||
((atom.loc.1 + 1 - min_y as u32) * TILE_SIZE) as i32 - pixel_y,
|
||||
);
|
||||
|
||||
// OOB handling
|
||||
|
|
@ -204,25 +223,29 @@ pub fn generate(
|
|||
rect.0 += (-loc.0) as u32;
|
||||
match rect.2.checked_sub((-loc.0) as u32) {
|
||||
Some(s) => rect.2 = s,
|
||||
None => continue 'atom // out of the viewport
|
||||
None => continue 'atom, // out of the viewport
|
||||
}
|
||||
loc.0 = 0;
|
||||
}
|
||||
while loc.0 + rect.2 as i32 > map_image.width as i32 {
|
||||
rect.2 -= 1;
|
||||
if rect.2 == 0 { continue 'atom }
|
||||
if rect.2 == 0 {
|
||||
continue 'atom;
|
||||
}
|
||||
}
|
||||
if loc.1 < 0 {
|
||||
rect.1 += (-loc.1) as u32;
|
||||
match rect.3.checked_sub((-loc.1) as u32) {
|
||||
Some(s) => rect.3 = s,
|
||||
None => continue 'atom // out of the viewport
|
||||
None => continue 'atom, // out of the viewport
|
||||
}
|
||||
loc.1 = 0;
|
||||
}
|
||||
while loc.1 + rect.3 as i32 > map_image.height as i32 {
|
||||
rect.3 -= 1;
|
||||
if rect.3 == 0 { continue 'atom }
|
||||
if rect.3 == 0 {
|
||||
continue 'atom;
|
||||
}
|
||||
}
|
||||
let loc = (loc.0 as u32, loc.1 as u32);
|
||||
|
||||
|
|
@ -259,7 +282,7 @@ pub fn get_atom_list<'a>(
|
|||
Some(x) => x,
|
||||
None => {
|
||||
println!("Warning: missing {:?}", fab.path);
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -316,7 +339,7 @@ impl<'a> Atom<'a> {
|
|||
type_: type_,
|
||||
prefab: None,
|
||||
vars: Default::default(),
|
||||
loc
|
||||
loc,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -349,7 +372,7 @@ pub trait GetVar {
|
|||
fn get_var_notnull<'a>(&'a self, key: &str, objtree: &'a ObjectTree) -> Option<&'a Constant> {
|
||||
match self.get_var_inner(key, objtree) {
|
||||
None | Some(&Constant::Null(_)) => None,
|
||||
Some(other) => Some(other)
|
||||
Some(other) => Some(other),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -466,7 +489,12 @@ pub fn color_of<T: GetVar + ?Sized>(objtree: &ObjectTree, atom: &T) -> [u8; 4] {
|
|||
if color.len() == 7 { // #rrggbb
|
||||
[(sum >> 16) as u8, (sum >> 8) as u8, sum as u8, alpha]
|
||||
} else if color.len() == 4 { // #rgb
|
||||
[(0x11 * ((sum >> 8) & 0xf)) as u8, (0x11 * ((sum >> 4) & 0xf)) as u8, (0x11 * (sum & 0xf)) as u8, alpha]
|
||||
[
|
||||
(0x11 * ((sum >> 8) & 0xf)) as u8,
|
||||
(0x11 * ((sum >> 4) & 0xf)) as u8,
|
||||
(0x11 * (sum & 0xf)) as u8,
|
||||
alpha,
|
||||
]
|
||||
} else {
|
||||
[255, 255, 255, alpha] // invalid
|
||||
}
|
||||
|
|
@ -515,7 +543,9 @@ fn calculate_adjacencies(ctx: Context, atom: &Atom, flags: i32) -> i32 {
|
|||
let check_one = |direction, flag| {
|
||||
if find_type_in_direction(ctx, atom, direction, flags) {
|
||||
flag
|
||||
} else { 0 }
|
||||
} else {
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
for &dir in &[SOUTH, NORTH, EAST, WEST] {
|
||||
|
|
@ -554,9 +584,12 @@ fn find_type_in_direction<'a>(ctx: Context, source: &Atom, direction: i32, flags
|
|||
let new_loc = (new_loc.0 as u32, new_loc.1 as u32);
|
||||
|
||||
// TODO: make this not call get_atom_list way too many times
|
||||
let atom_list = get_atom_list(ctx.objtree,
|
||||
let atom_list = get_atom_list(
|
||||
ctx.objtree,
|
||||
&ctx.map.dictionary[&ctx.grid[ndarray::Dim([new_loc.1 as usize, new_loc.0 as usize])]],
|
||||
new_loc, ctx.render_passes);
|
||||
new_loc,
|
||||
ctx.render_passes,
|
||||
);
|
||||
match source.get_var("canSmoothWith", ctx.objtree) {
|
||||
&Constant::List(ref elements) => if flags & SMOOTH_MORE != 0 {
|
||||
// smooth with canSmoothWith + subtypes
|
||||
|
|
@ -630,21 +663,21 @@ fn cardinal_smooth<'a>(output: &mut Vec<Atom<'a>>, ctx: Context<'a>, source: &At
|
|||
}
|
||||
|
||||
fn diagonal_smooth<'a>(output: &mut Vec<Atom<'a>>, ctx: Context<'a>, source: &Atom<'a>, adjacencies: i32) {
|
||||
let presets = if adjacencies == N_NORTH|N_WEST {
|
||||
let presets = if adjacencies == N_NORTH | N_WEST {
|
||||
["d-se", "d-se-0"]
|
||||
} else if adjacencies == N_NORTH|N_EAST {
|
||||
} else if adjacencies == N_NORTH | N_EAST {
|
||||
["d-sw", "d-sw-0"]
|
||||
} else if adjacencies == N_SOUTH|N_WEST {
|
||||
} else if adjacencies == N_SOUTH | N_WEST {
|
||||
["d-ne", "d-ne-0"]
|
||||
} else if adjacencies == N_SOUTH|N_EAST {
|
||||
} else if adjacencies == N_SOUTH | N_EAST {
|
||||
["d-nw", "d-nw-0"]
|
||||
} else if adjacencies == N_NORTH|N_WEST|N_NORTHWEST {
|
||||
} else if adjacencies == N_NORTH | N_WEST | N_NORTHWEST {
|
||||
["d-se", "d-se-1"]
|
||||
} else if adjacencies == N_NORTH|N_EAST|N_NORTHEAST {
|
||||
} else if adjacencies == N_NORTH | N_EAST | N_NORTHEAST {
|
||||
["d-sw", "d-sw-1"]
|
||||
} else if adjacencies == N_SOUTH|N_WEST|N_SOUTHWEST {
|
||||
} else if adjacencies == N_SOUTH | N_WEST | N_SOUTHWEST {
|
||||
["d-ne", "d-ne-1"]
|
||||
} else if adjacencies == N_SOUTH|N_EAST|N_SOUTHEAST {
|
||||
} else if adjacencies == N_SOUTH | N_EAST | N_SOUTHEAST {
|
||||
["d-nw", "d-nw-1"]
|
||||
} else {
|
||||
return cardinal_smooth(output, ctx, source, adjacencies);
|
||||
|
|
@ -653,7 +686,11 @@ fn diagonal_smooth<'a>(output: &mut Vec<Atom<'a>>, ctx: Context<'a>, source: &At
|
|||
// turf underneath
|
||||
if subtype(&source.type_.path, "/turf/closed/wall/") {
|
||||
// BYOND memes
|
||||
if source.get_var("fixed_underlay", ctx.objtree).index(&Constant::string("space")).is_some() {
|
||||
if source
|
||||
.get_var("fixed_underlay", ctx.objtree)
|
||||
.index(&Constant::string("space"))
|
||||
.is_some()
|
||||
{
|
||||
output.push(Atom::from_type(ctx.objtree, "/turf/open/space/basic", source.loc).unwrap());
|
||||
} else {
|
||||
let dir = flip(reverse_ndir(adjacencies));
|
||||
|
|
@ -666,9 +703,12 @@ fn diagonal_smooth<'a>(output: &mut Vec<Atom<'a>>, ctx: Context<'a>, source: &At
|
|||
if !(new_loc.0 < 0 || new_loc.1 < 0 || new_loc.0 >= dim_x as i32 || new_loc.1 >= dim_y as i32) {
|
||||
let new_loc = (new_loc.0 as u32, new_loc.1 as u32);
|
||||
// TODO: make this not call get_atom_list way too many times
|
||||
let atom_list = get_atom_list(ctx.objtree,
|
||||
let atom_list = get_atom_list(
|
||||
ctx.objtree,
|
||||
&ctx.map.dictionary[&ctx.grid[ndarray::Dim([new_loc.1 as usize, new_loc.0 as usize])]],
|
||||
new_loc, ctx.render_passes);
|
||||
new_loc,
|
||||
ctx.render_passes,
|
||||
);
|
||||
for mut atom in atom_list {
|
||||
if subtype(&atom.type_.path, "/turf/open/") {
|
||||
atom.loc = source.loc;
|
||||
|
|
@ -730,14 +770,14 @@ fn flip(direction: i32) -> i32 {
|
|||
|
||||
fn reverse_ndir(ndir: i32) -> i32 {
|
||||
use dmi::*;
|
||||
const NW1: i32 = N_NORTH|N_WEST;
|
||||
const NW2: i32 = NW1|N_NORTHWEST;
|
||||
const NE1: i32 = N_NORTH|N_EAST;
|
||||
const NE2: i32 = NE1|N_NORTHEAST;
|
||||
const SW1: i32 = N_SOUTH|N_WEST;
|
||||
const SW2: i32 = SW1|N_SOUTHWEST;
|
||||
const SE1: i32 = N_SOUTH|N_EAST;
|
||||
const SE2: i32 = SE1|N_SOUTHEAST;
|
||||
const NW1: i32 = N_NORTH | N_WEST;
|
||||
const NW2: i32 = NW1 | N_NORTHWEST;
|
||||
const NE1: i32 = N_NORTH | N_EAST;
|
||||
const NE2: i32 = NE1 | N_NORTHEAST;
|
||||
const SW1: i32 = N_SOUTH | N_WEST;
|
||||
const SW2: i32 = SW1 | N_SOUTHWEST;
|
||||
const SE1: i32 = N_SOUTH | N_EAST;
|
||||
const SE2: i32 = SE1 | N_SOUTHEAST;
|
||||
|
||||
match ndir {
|
||||
N_NORTH => NORTH,
|
||||
|
|
@ -781,4 +821,3 @@ fn right_45(dir: i32) -> i32 {
|
|||
e => e,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,8 @@ impl RenderPass for HideInvisible {
|
|||
#[derive(Default)]
|
||||
pub struct FakeGlass;
|
||||
impl RenderPass for FakeGlass {
|
||||
fn overlays<'a>(&self,
|
||||
fn overlays<'a>(
|
||||
&self,
|
||||
atom: &mut Atom<'a>,
|
||||
_objtree: &'a ObjectTree,
|
||||
underlays: &mut Vec<Atom<'a>>,
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ impl RenderPass for Random {
|
|||
for child in root.children() {
|
||||
if let Some(v) = child.vars.get("hidden") {
|
||||
if !v.value.constant.as_ref().map_or(false, |c| c.to_bool()) {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(icon) = child.vars.get("icon") {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ impl RenderPass for TransitTube {
|
|||
use dmi::*;
|
||||
|
||||
if !atom.istype("/obj/structure/transit_tube/") {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let dir = atom.get_var("dir", objtree).to_int().unwrap_or(::dmi::SOUTH);
|
||||
|
|
@ -95,7 +95,13 @@ impl RenderPass for TransitTube {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_tube_overlay<'a>(output: &mut Vec<Atom<'a>>, objtree: &'a ObjectTree, source: &Atom<'a>, dir: i32, shift: i32) {
|
||||
fn create_tube_overlay<'a>(
|
||||
output: &mut Vec<Atom<'a>>,
|
||||
objtree: &'a ObjectTree,
|
||||
source: &Atom<'a>,
|
||||
dir: i32,
|
||||
shift: i32,
|
||||
) {
|
||||
use dmi::*;
|
||||
|
||||
let mut copy = Atom::from_type(objtree, "/atom", source.loc).unwrap();
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ use walkdir::{DirEntry, WalkDir};
|
|||
use dmm_tools::*;
|
||||
|
||||
fn is_visible(entry: &DirEntry) -> bool {
|
||||
entry.path()
|
||||
entry
|
||||
.path()
|
||||
.file_name()
|
||||
.unwrap_or("".as_ref())
|
||||
.to_str()
|
||||
|
|
@ -22,10 +23,7 @@ fn files_with_extension<F: FnMut(&Path)>(ext: &str, mut f: F) {
|
|||
return;
|
||||
}
|
||||
};
|
||||
for entry in WalkDir::new(dir)
|
||||
.into_iter()
|
||||
.filter_entry(is_visible)
|
||||
{
|
||||
for entry in WalkDir::new(dir).into_iter().filter_entry(is_visible) {
|
||||
let entry = entry.unwrap();
|
||||
if entry.file_type().is_file() && entry.path().extension() == Some(ext.as_ref()) {
|
||||
let path = entry.path();
|
||||
|
|
|
|||
|
|
@ -24,8 +24,12 @@ impl<R: Read> Iterator for Chars<R> {
|
|||
Some(Err(e)) => return Some(Err(e)),
|
||||
};
|
||||
let width = utf8_char_width(first_byte);
|
||||
if width == 1 { return Some(Ok(first_byte as char)) }
|
||||
if width == 0 { return Some(Err(ErrorKind::InvalidData.into())) }
|
||||
if width == 1 {
|
||||
return Some(Ok(first_byte as char));
|
||||
}
|
||||
if width == 0 {
|
||||
return Some(Err(ErrorKind::InvalidData.into()));
|
||||
}
|
||||
let mut buf = [first_byte, 0, 0, 0];
|
||||
{
|
||||
let mut start = 1;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue