Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Replace eval with bytecode-based VM #3307

Closed
wants to merge 103 commits into from
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
4907717
Initial work
Dherse Jan 23, 2024
1ca3c63
Before rewrite
Dherse Jan 27, 2024
f2d0508
Initial new VM
Dherse Jan 30, 2024
370d5bd
Fixed instruction decoding & rules
Dherse Jan 30, 2024
c00cfeb
Fixed jumps in scopes
Dherse Jan 30, 2024
41fab3e
Lots of fixes for compile, iter, etc.
Dherse Jan 30, 2024
c3a51db
Fixed writable access
Dherse Jan 30, 2024
82f6a29
cargo fmt
Dherse Jan 30, 2024
a2d9ba3
Fixed loops
Dherse Jan 30, 2024
e64ddad
Fixed loop (again)
Dherse Jan 30, 2024
d99fe29
Fixed condition & loops
Dherse Jan 31, 2024
798327a
cargo fmt
Dherse Jan 31, 2024
d04bf41
Fixed control flow
Dherse Jan 31, 2024
6b998f3
Cheaper `Opcode::Flow` (no span)
Dherse Jan 31, 2024
6fdf9ee
Fixed export & capturing duplicates
Dherse Jan 31, 2024
9ec4037
Fixed recursive module call weirdness
Dherse Jan 31, 2024
00cd913
Fixed label attachment
Dherse Jan 31, 2024
355b843
Fix show rule, fixed set and show (join), fixed break
Dherse Jan 31, 2024
c18933e
Removed logging
Dherse Jan 31, 2024
d5da17b
Fix pattern capture fail, fix no display in markup
Dherse Feb 1, 2024
748d236
Fixed messy decoding-encoding
Dherse Feb 2, 2024
8217c44
Fixed jumps, duplicate consts, etc.
Dherse Feb 3, 2024
5bcaeb3
Fixed jumps once and for all!
Dherse Feb 3, 2024
116f4e4
Variable # of registers, reuse regs
Dherse Feb 3, 2024
33350e4
cargo fmt
Dherse Feb 3, 2024
762235a
Simplify & speed
Dherse Feb 3, 2024
7e24092
Smallvec & stacker
Dherse Feb 3, 2024
1a406d1
Improved looping performance
Dherse Feb 3, 2024
82c5046
Improved opcode caching (yes really)
Dherse Feb 3, 2024
6c74666
Fixed small error
Dherse Feb 3, 2024
a9ec993
Removed `eval` module
Dherse Feb 3, 2024
79e7dd6
Starting fixing removal of eval
Dherse Feb 3, 2024
62d6d76
Add a few manual Debug impls to elements
laurmaedje Jan 17, 2024
edcafa9
Fix emptyness check in `into_par_items`
laurmaedje Jan 17, 2024
69466e9
Handle metadata application where styles are managed
laurmaedje Jan 17, 2024
1b1587c
Add `Page` struct
laurmaedje Jan 17, 2024
680f725
Cleaner separation between single and multi-region layout
laurmaedje Jan 18, 2024
170f4ad
Renamed `diff` symbol to `partial` (#3211)
Andrew15-5 Jan 18, 2024
f94864d
Add `gt.approx`, `gt.napprox`, `lt.approx`, `lt.napprox` and `colon.d…
MDLC01 Jan 24, 2024
4a78163
Handle `Finalize` alongside `Synthesize`
laurmaedje Jan 24, 2024
b6f0624
Remove guards for built-in elements
laurmaedje Jan 24, 2024
cc57fec
More efficient guard storage
laurmaedje Jan 24, 2024
d25842f
Implement bitwise operations on integers (#3130)
PgBiel Jan 25, 2024
8402e31
Add explanation of show rule scope in footnote (#3187)
mkpoli Jan 25, 2024
b0170ee
Add symbol name for narrow non-breaking space (#3217)
t-rapp Jan 25, 2024
3db3e57
Fix PDF export of grayscale image (#3219)
LaurenzV Jan 25, 2024
5f72abe
Make `math.class` affect the limit configuration (#3231)
MDLC01 Jan 25, 2024
d704c42
Make typst's advanced color public (#3234)
Myriad-Dreamin Jan 25, 2024
e68679a
doc: remove inaccurate statement in eval (#3250)
Enter-tainer Jan 25, 2024
d3e1d2a
Include units in top-level SVG element (#3233)
artemist Jan 25, 2024
93b36fc
Merging cells: Colspans [More Flexible Tables Pt.3a] (#3239)
PgBiel Jan 25, 2024
986f5c9
Bump resvg + svg2pdf and add support for filters (#3254)
LaurenzV Jan 25, 2024
fc63590
Add missing Chinese counting symbols to documentation (#3264)
zica87 Jan 26, 2024
302c6ed
Refactor math styling to bring it closer to normal styling (#3262)
laurmaedje Jan 26, 2024
e60e061
Configure ureq to use sytem-native TLS (#3258)
laurmaedje Jan 26, 2024
55e3fb7
Do not parse special spaces to Space Token (#3267)
peng1999 Jan 29, 2024
7a02c0b
Link to `datetime` from `datetime.display` docs (#3270)
tertsdiepraam Jan 29, 2024
29bdcba
Add `openssl` to dependencies in `flake.nix` (#3285)
s-cerevisiae Jan 29, 2024
98bf4f7
Merge `Fields` and `ElementFields` traits
laurmaedje Jan 29, 2024
26ace35
Refactor capability helpers
laurmaedje Jan 29, 2024
5491531
Raise Rust version to 1.74
laurmaedje Jan 29, 2024
4a175cd
Remove an unnecessary clone in loop evaluation (#3297)
Leedehai Jan 30, 2024
0aad47e
Fix an error of uncastable dict input (#3247)
Leedehai Jan 30, 2024
3f5c6b2
Refactor folding (#3294)
laurmaedje Jan 30, 2024
5bc5059
Refactor `#[elem]` macro (#3303)
laurmaedje Jan 30, 2024
82f34ea
Respect set rules in where selectors (#3290)
laurmaedje Jan 30, 2024
84dedb8
Document how to cite sources with special characters. (#3261)
01mf02 Jan 30, 2024
e304c76
nix: bump nixpkgs (#3305)
cmoog Jan 30, 2024
de518c2
Adjust for-loop's pattern matching rules (#3308)
Leedehai Jan 31, 2024
192644b
Use alternate screen and refactor terminal output. (#2665)
frozolotl Jan 31, 2024
252ea9b
Ensure synthesized field access never panics (#3310)
laurmaedje Jan 31, 2024
bf00314
Fix show-set semantics (#3311)
laurmaedje Feb 1, 2024
050bb03
Introduce override list to FontInfo (#3228)
peng1999 Feb 1, 2024
8788938
Allow for-loop to iterate over bytes (#3317)
Leedehai Feb 2, 2024
fbc7757
Let for-loop iterate Dict with an iterator (#3318)
Leedehai Feb 2, 2024
e9cd05c
Fix style issue for Latin Modern (#3315)
peng1999 Feb 2, 2024
9be1c47
Use heading's own location for numbering (#3322)
laurmaedje Feb 2, 2024
2dc9c9c
font-exceptions: override weight of Arial Black (#3321)
mkroening Feb 2, 2024
4cea772
Support for and/or selectors in show rules (#3326)
laurmaedje Feb 2, 2024
8786b38
Before rewrite
Dherse Jan 27, 2024
3e6ded3
Initial new VM
Dherse Jan 30, 2024
eec8560
Fixed label attachment
Dherse Jan 31, 2024
747c46d
Fix show rule, fixed set and show (join), fixed break
Dherse Jan 31, 2024
6eb4fa3
Merge remote-tracking branch 'upstream/main' into bytecode-vm
Dherse Feb 4, 2024
c7658fe
Fix merge & fmt
Dherse Feb 4, 2024
3f8216f
Fixed module import
Dherse Feb 5, 2024
a3425d2
Fixed cyclic import
Dherse Feb 5, 2024
7ec3a13
Fix performance
Dherse Feb 5, 2024
5ec67c3
Optimizations
Dherse Feb 5, 2024
2d46781
Simplification & opt
Dherse Feb 5, 2024
6b7a5bc
Various attempts at optimization
Dherse Feb 6, 2024
7709042
Removed unsafe
Dherse Feb 6, 2024
66c81a1
Optimization bonanza
Dherse Feb 6, 2024
9099196
Haha optimizations goes brrrrrrrrrrrrrrr
Dherse Feb 7, 2024
072ab62
`PicoStr` goes brrr & simplification
Dherse Feb 8, 2024
e8cf94b
Fixed arg span
Dherse Feb 8, 2024
67e0fdd
Massive compiler cleanup & simplification
Dherse Feb 8, 2024
ef55cca
Further cleanup
Dherse Feb 8, 2024
4dc43e7
Cleanup `Call` opcode
Dherse Feb 8, 2024
f829d3f
Fixed state
Dherse Feb 8, 2024
7cff984
Improved efficiency
Dherse Feb 9, 2024
6994b6a
Working on things
Dherse Feb 18, 2024
4808ad3
Missing file
Dherse Feb 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ typst-timing = { path = "crates/typst-timing" }
az = "1.2"
base64 = "0.21.2"
bitflags = { version = "2", features = ["serde"] }
bytemuck = "1"
bytemuck = { version = "1.14", features = [ "derive" ] }
chinese-number = { version = "0.7.2", default-features = false, features = ["number-to-chinese"] }
chrono = { version = "0.4.24", default-features = false, features = ["clock", "std"] }
ciborium = "0.2.1"
Expand Down
1 change: 1 addition & 0 deletions crates/typst-syntax/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ doctest = false
bench = false

[dependencies]
bytemuck = { workspace = true }
comemo = { workspace = true }
ecow = { workspace = true }
once_cell = { workspace = true }
Expand Down
4 changes: 3 additions & 1 deletion crates/typst-syntax/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::path::{Component, Path, PathBuf};
use std::str::FromStr;
use std::sync::RwLock;

use bytemuck::{Pod, Zeroable};
use ecow::{eco_format, EcoString};
use once_cell::sync::Lazy;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
Expand All @@ -28,7 +29,8 @@ type Pair = &'static (Option<PackageSpec>, VirtualPath);
/// Identifies a file in a project or package.
///
/// This type is globally interned and thus cheap to copy, compare, and hash.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Pod, Zeroable)]
#[repr(transparent)]
pub struct FileId(u16);

impl FileId {
Expand Down
15 changes: 15 additions & 0 deletions crates/typst-syntax/src/span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::FileId;
/// This type takes up 8 bytes and is null-optimized (i.e. `Option<Span>` also
/// takes 8 bytes).
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct Span(NonZeroU64);

impl Span {
Expand Down Expand Up @@ -54,6 +55,20 @@ impl Span {
}
}

/// Create a new span from its raw representation.
///
/// # Safety
///
/// The raw representation must be a valid span.
pub const unsafe fn new_unchecked(number: NonZeroU64) -> Self {
Self(number)
}

/// Get the raw representation of this span.
pub const fn as_raw(self) -> NonZeroU64 {
self.0
}

/// Create a span that does not point into any source file.
pub const fn detached() -> Self {
match NonZeroU64::new(Self::DETACHED) {
Expand Down
1 change: 1 addition & 0 deletions crates/typst/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ typst-syntax = { workspace = true }
typst-timing = { workspace = true }
az = { workspace = true }
bitflags = { workspace = true }
bytemuck = { workspace = true }
chinese-number = { workspace = true }
ciborium = { workspace = true }
comemo = { workspace = true }
Expand Down
166 changes: 166 additions & 0 deletions crates/typst/src/compiler/access.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use std::sync::Arc;

use ecow::EcoString;
use typst_syntax::ast::{self, AstNode};

use super::{Compile, Compiler, ReadableGuard, WritableGuard};
use crate::diag::{bail, At, SourceResult};
use crate::engine::Engine;
use crate::vm::Access as VmAccess;

#[derive(Debug, Clone)]
pub enum AccessPattern {
/// Access this value through a readable.
Readable(ReadableGuard),

/// Access this value through a writeable.
Writable(WritableGuard),

/// Access this value through a chained access.
Chained(Arc<Self>, EcoString),

/// Access this value through an accessor method.
AccessorMethod(Arc<Self>, EcoString, ReadableGuard),
}

impl AccessPattern {
pub fn as_vm_access(&self) -> VmAccess {
match self {
AccessPattern::Readable(r) => VmAccess::Readable(r.as_readable()),
AccessPattern::Writable(w) => VmAccess::Writable(w.as_writable()),
AccessPattern::Chained(other, v) => {
VmAccess::Chained(Arc::new(other.as_vm_access()), v.clone())
}
AccessPattern::AccessorMethod(other, v, r) => VmAccess::AccessorMethod(
Arc::new(other.as_vm_access()),
v.clone(),
r.as_readable(),
),
}
}
}

pub trait Access {
/// Generate an access to the value.
fn access<'a>(
self,
engine: &mut Engine,
compiler: &'a mut Compiler,
mutable: bool,
) -> SourceResult<AccessPattern>;
}

impl Access for ast::Expr<'_> {
fn access<'a>(
self,
engine: &mut Engine,
compiler: &'a mut Compiler,
mutable: bool,
) -> SourceResult<AccessPattern> {
match self {
Self::Ident(v) => v.access(engine, compiler, mutable),
Self::Parenthesized(v) => v.access(engine, compiler, mutable),
Self::FieldAccess(v) => v.access(engine, compiler, mutable),
Self::FuncCall(v) => v.access(engine, compiler, mutable),
_ if mutable => {
bail!(self.span(), "cannot mutate a temporary value");
}
other => {
let value = other.compile(engine, compiler)?;
Ok(AccessPattern::Readable(value))
}
}
}
}

impl Access for ast::Ident<'_> {
fn access<'a>(
self,
_: &mut Engine,
compiler: &'a mut Compiler,
mutable: bool,
) -> SourceResult<AccessPattern> {
match compiler.read(self.span(), self.get()).at(self.span())? {
Some(ReadableGuard::Register(reg)) => {
if mutable {
Ok(AccessPattern::Writable(reg.into()))
} else {
Ok(AccessPattern::Readable(reg.into()))
}
}
Some(ReadableGuard::Parent(parent)) => {
if mutable {
Ok(AccessPattern::Writable(parent.into()))
} else {
Ok(AccessPattern::Readable(parent.into()))
}
}
Some(ReadableGuard::Captured(cap)) => {
if mutable {
bail!(self.span(), "cannot mutate a captured value")
} else {
Ok(AccessPattern::Readable(cap.into()))
}
}
Some(ReadableGuard::Global(global)) => {
if mutable {
bail!(self.span(), "cannot mutate a global value")
} else {
Ok(AccessPattern::Readable(global.into()))
}
}
None => bail!(self.span(), "could not find `{}` in scope", self.get()),
_ => unreachable!(),
}
}
}

impl Access for ast::Parenthesized<'_> {
fn access<'a>(
self,
engine: &mut Engine,
compiler: &'a mut Compiler,
mutable: bool,
) -> SourceResult<AccessPattern> {
self.expr().access(engine, compiler, mutable)
}
}

impl Access for ast::FieldAccess<'_> {
fn access<'a>(
self,
engine: &mut Engine,
compiler: &'a mut Compiler,
mutable: bool,
) -> SourceResult<AccessPattern> {
let left = self.target().access(engine, compiler, mutable)?;
Ok(AccessPattern::Chained(Arc::new(left), self.field().get().clone()))
}
}

impl Access for ast::FuncCall<'_> {
fn access<'a>(
self,
engine: &mut Engine,
compiler: &'a mut Compiler,
mutable: bool,
) -> SourceResult<AccessPattern> {
if !mutable {
// Compile the function call.
let call = self.compile(engine, compiler)?;
Ok(AccessPattern::Readable(call))
} else if let ast::Expr::FieldAccess(access) = self.callee() {
// Compile the arguments.
let args = self.args();
let args = args.compile(engine, compiler)?;

// Ensure that the arguments live long enough.
let left = access.target().access(engine, compiler, mutable)?;

let method = access.field();
Ok(AccessPattern::AccessorMethod(Arc::new(left), method.get().clone(), args))
} else {
bail!(self.span(), "cannot mutate a temporary value")
}
}
}