Skip to content

Commit 6608a68

Browse files
committed
migrate few files + submodule
- YarnSpinner.Compiler/Declaration.cs - YarnSpinner.Compiler/DeclarationVisitor.cs - YarnSpinner.Compiler/StringTableManager.cs - YarnSpinner.Compiler/Utility.cs
1 parent 3c6b48d commit 6608a68

10 files changed

Lines changed: 122 additions & 25 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/compiler/Cargo.toml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ version = "0.7.0"
44
edition = "2024"
55
repository = "https://github.com/YarnSpinnerTool/YarnSpinner-Rust"
66
homepage = "https://docs.yarnspinner.dev/"
7-
categories = ["game-development", "compilers"]
8-
authors = ["Jan Hohenheim <jan@hohenheim.ch>"]
7+
categories = [ "game-development", "compilers" ]
8+
authors = [ "Jan Hohenheim <jan@hohenheim.ch>" ]
99
license = "MIT OR Apache-2.0"
1010
description = "Compiler for Yarn Spinner for Rust, the friendly tool for writing game dialogue"
1111

1212
[features]
13-
default = []
14-
serde = ["dep:serde", "bevy?/serialize", "yarnspinner_core/serde"]
15-
bevy = ["dep:bevy", "yarnspinner_core/bevy"]
13+
default = [ ]
14+
serde = [ "dep:serde", "bevy?/serialize", "yarnspinner_core/serde" ]
15+
bevy = [ "dep:bevy", "yarnspinner_core/bevy" ]
1616

1717
[dependencies]
1818
antlr-rust = "=0.3.0-beta"
@@ -21,9 +21,10 @@ regex = "1"
2121
yarnspinner_internal_shared = { path = "../internal_shared", version = "0.1.0" }
2222
yarnspinner_core = { path = "../core", version = "0.7.0" }
2323
annotate-snippets = "0.10"
24-
serde = { version = "1", features = ["derive"], optional = true }
24+
serde = { version = "1", features = [ "derive" ], optional = true }
2525
bevy = { version = "0.18", default-features = false, optional = true }
26-
rand = { version = "0.9", features = ["small_rng"] }
26+
rand = { version = "0.9", features = [ "small_rng" ] }
27+
crc32fast = "1.5.0"
2728

2829
[target.'cfg(target_arch = "wasm32")'.dependencies]
2930
instant = { version = "0.1.12", features = [

crates/compiler/src/compilation_steps/validate_unique_inferred_variable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub(crate) fn validate_unique_inferred_variables(
1111
let duplicate_inferred_vars = state
1212
.known_variable_declarations
1313
.iter()
14-
.filter(|&d| !matches!(d.r#type, Type::Function(_)))
14+
.filter(|&d| d.is_variable())
1515
.fold(HashMap::<&str, Vec<&Declaration>>::new(), |mut acc, d| {
1616
acc.entry(&d.name).or_default().push(d);
1717
acc

crates/compiler/src/compiler/add_tags_to_lines.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@ impl Compiler {
2626
/// collection.
2727
///
2828
/// ## Return value
29-
/// Returns he modified source code, with line tags added.
29+
/// Returns the modified source code, with line tags added.
3030
/// If all nodes already have line tags, returns `None`.
31+
#[deprecated(
32+
note = "This method doesn't return the new tags, just the modified text which can cause issues with multiple files. Please use TagLines instead"
33+
)]
3134
pub fn add_tags_to_lines(
3235
contents: impl Into<String>,
3336
existing_line_tags: Vec<LineId>,
@@ -66,6 +69,71 @@ impl Compiler {
6669
Ok(None)
6770
}
6871
}
72+
73+
/// Given Yarn source code, adds line tags to the ends of all lines
74+
/// that need one and do not already have one.
75+
///
76+
/// This method ensures that it does not generate line
77+
/// tags that are already present in the file, or present in the
78+
/// `existing_line_tags` collection.
79+
///
80+
/// Line tags are added to any line of source code that contains
81+
/// user-visible text: lines, options, and shortcut options.
82+
///
83+
/// ## Parameters
84+
///
85+
/// `contents`: The source code to add line tags
86+
/// to.
87+
/// `existing_line_tags`: The collection of line tags
88+
/// already exist elsewhere in the source code; the newly added
89+
/// line tags will not be duplicates of any in this
90+
/// collection.
91+
///
92+
/// ## Return value
93+
/// Returns Tuple of the modified source code, with line tags
94+
/// added and the list of new line tags generated.
95+
pub fn tag_lines(
96+
contents: impl Into<String>,
97+
existing_line_tags: Vec<LineId>,
98+
) -> crate::Result<Option<(String, Vec<LineId>)>> {
99+
let contents = contents.into();
100+
let chars: Vec<_> = contents.chars().map(|c| c as u32).collect();
101+
// First, get the parse tree for this source code.
102+
let file = File {
103+
file_name: "<input>".to_string(),
104+
source: contents,
105+
};
106+
let (parse_source, diagnostics) = parse_source(&file, &chars);
107+
let tree = parse_source.tree.clone();
108+
// Were there any error-level diagnostics?
109+
if diagnostics.has_errors() {
110+
// We encountered a parse error. Bail here; we aren't confident in our ability to correctly insert a line tag.
111+
return Err(CompilerError(diagnostics));
112+
}
113+
114+
// Create the line listener, which will produce TextReplacements for each new line tag.
115+
let untagged_line_listener =
116+
Box::new(UntaggedLineListener::new(existing_line_tags, parse_source));
117+
let rewritten_nodes = untagged_line_listener.rewritten_lines.clone();
118+
let rewrote_anything = untagged_line_listener.rewrote_anything.clone();
119+
120+
// Walk the tree with this listener, and generate text replacements containing line tags.
121+
let untagged_line_listener =
122+
YarnSpinnerParserTreeWalker::walk(untagged_line_listener, tree.as_ref());
123+
// Apply these text replacements to the original source and return it.
124+
125+
if rewrote_anything.load(Ordering::Relaxed) {
126+
let result = rewritten_nodes.take();
127+
let mut string = result.join("\n");
128+
string.push('\n');
129+
Ok(Some((
130+
string,
131+
untagged_line_listener.existing_line_tags.clone(),
132+
)))
133+
} else {
134+
Ok(None)
135+
}
136+
}
69137
}
70138

71139
/// Parses a string of Yarn source code, and produces a [`FileParseResult`]

crates/compiler/src/listeners/untagged_line_listener.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::rc::Rc;
1818
use std::sync::atomic::AtomicBool;
1919

2020
pub(crate) struct UntaggedLineListener<'input> {
21-
existing_line_tags: Vec<LineId>,
21+
pub(crate) existing_line_tags: Vec<LineId>,
2222
file: FileParseResult<'input>,
2323
pub(crate) rewritten_lines: Rc<RefCell<Vec<String>>>,
2424
pub(crate) rewrote_anything: Rc<AtomicBool>,

crates/compiler/src/output/declaration.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ impl Declaration {
171171
_ => false,
172172
}
173173
}
174+
175+
/// Gets a value indicating whether this Declaration represents a variable.
176+
pub fn is_variable(&self) -> bool {
177+
!matches!(self.r#type, Type::Function(_))
178+
}
174179
}
175180

176181
/// The source of a declaration.

crates/compiler/src/string_table_manager.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
33
use crate::output::StringInfo;
44
use crate::prelude::*;
5+
use crc32fast;
56
use std::collections::HashMap;
67
use std::ops::{Deref, DerefMut};
78
use yarnspinner_core::prelude::*;
89

10+
const MAX_ATTEMPTS: usize = 1000;
11+
912
#[derive(Debug, Clone, Default)]
1013
pub(crate) struct StringTableManager(pub HashMap<LineId, StringInfo>);
1114

@@ -33,13 +36,28 @@ impl StringTableManager {
3336
};
3437
(line_id, string_info)
3538
} else {
36-
let line_id = format!(
37-
"{LINE_ID_PREFIX}{}-{}-{}",
39+
let candidate_seed = format!(
40+
"{}{}{}",
3841
string_info.file_name,
3942
string_info.node_name,
4043
self.len()
41-
)
42-
.into();
44+
);
45+
46+
let line_id = (0..=MAX_ATTEMPTS)
47+
.find_map(|count| {
48+
let with_suffix = if count == 0 {
49+
candidate_seed.as_str().to_owned()
50+
} else {
51+
format!("{candidate_seed}{count}")
52+
};
53+
54+
let id =
55+
format!("{LINE_ID_PREFIX}{}", crc32fast::hash(with_suffix.as_bytes())).into();
56+
57+
(!self.contains_key(&id)).then_some(id)
58+
})
59+
.expect(&format!("Internal error: string table failed to find a non-colliding hash for \"{candidate_seed}\" after {MAX_ATTEMPTS} attempts"));
60+
4361
let string_info = StringInfo {
4462
is_implicit_tag: true,
4563
..string_info

crates/compiler/src/visitors/declaration_visitor.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,10 @@ impl<'input> YarnSpinnerParserVisitorCompat<'input> for DeclarationVisitor<'inpu
142142
// Figure out the value and its type
143143
let mut constant_value_visitor =
144144
ConstantValueVisitor::new(self.diagnostics.clone(), self.file.clone());
145-
let value_context = ctx.value().unwrap();
145+
let Some(value_context) = ctx.value() else {
146+
// no value was provided, declare as undefined and continue
147+
return;
148+
};
146149
let value = constant_value_visitor.visit(value_context.as_ref());
147150
self.diagnostics
148151
.extend_from_slice(&constant_value_visitor.diagnostics);

readme.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,13 @@ cargo run
135135

136136
## Version Table
137137

138-
| Bevy | Yarn Spinner for Rust |
139-
|-------------|---------------------- |
140-
| 0.18 | 0.7 |
141-
| 0.17 | 0.6 |
142-
| 0.16 | 0.5 |
143-
| 0.15 | 0.4 |
144-
| 0.14 | 0.3 |
145-
| 0.13 | 0.2 |
146-
| 0.12 | 0.1 |
138+
| Bevy | Yarn Spinner for Rust | Yarn Spinner |
139+
|-------------|---------------------- |--------------|
140+
| 0.18 | main | 2.5.0 |
141+
| 0.18 | 0.7 | 2.3.0 |
142+
| 0.17 | 0.6 | 2.3.0 |
143+
| 0.16 | 0.5 | 2.3.0 |
144+
| 0.15 | 0.4 | 2.3.0 |
145+
| 0.14 | 0.3 | 2.3.0 |
146+
| 0.13 | 0.2 | 2.3.0 |
147+
| 0.12 | 0.1 | 2.3.0 |

third-party/YarnSpinner

Submodule YarnSpinner updated 157 files

0 commit comments

Comments
 (0)