Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


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

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ rue-lexer = { path = "crates/rue-lexer", version = "0.9.0" }
rue-parser = { path = "crates/rue-parser", version = "0.9.0" }
rue-diagnostic = { path = "crates/rue-diagnostic", version = "0.9.0" }
rue-ast = { path = "crates/rue-ast", version = "0.9.0" }
rue-formatter = { path = "crates/rue-formatter", version = "0.9.0" }
rue-compiler = { path = "crates/rue-compiler", version = "0.9.0" }
rue-options = { path = "crates/rue-options", version = "0.9.0" }
rue-lir = { path = "crates/rue-lir", version = "0.9.0" }
Expand Down
3 changes: 3 additions & 0 deletions crates/rue-ast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ workspace = true
[dependencies]
rue-parser = { workspace = true }
paste = { workspace = true }

[dev-dependencies]
num-traits = { workspace = true }
84 changes: 82 additions & 2 deletions crates/rue-ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,47 @@ pub trait AstNode {
}

macro_rules! ast_nodes {
($( $kind:ident),+ $(,)?) => { paste! { $(
($( $kind:ident),+ $(,)?) => { paste! {
/// The exhaustive set of syntax kinds with typed AST node wrappers.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AstNodeKind {
$( $kind, )+
}

impl AstNodeKind {
pub const ALL: &'static [Self] = &[
$( Self::$kind, )+
];

pub fn from_syntax(kind: SyntaxKind) -> Option<Self> {
match kind {
$( SyntaxKind::$kind => Some(Self::$kind), )+
_ => None,
}
}

pub fn of(node: &SyntaxNode) -> Option<Self> {
Self::from_syntax(node.kind())
}
}

impl TryFrom<SyntaxKind> for AstNodeKind {
type Error = SyntaxKind;

fn try_from(kind: SyntaxKind) -> Result<Self, Self::Error> {
Self::from_syntax(kind).ok_or(kind)
}
}

impl From<AstNodeKind> for SyntaxKind {
fn from(kind: AstNodeKind) -> Self {
match kind {
$( AstNodeKind::$kind => Self::$kind, )+
}
}
}

$(
#[derive(Debug, Clone)]
pub struct [< Ast $kind >](SyntaxNode);

Expand All @@ -26,7 +66,8 @@ macro_rules! ast_nodes {
&self.0
}
}
)+ } };
)+
} };
}

macro_rules! ast_enum {
Expand Down Expand Up @@ -900,3 +941,42 @@ impl AstStructFieldBinding {
self.syntax().children().find_map(AstBinding::cast)
}
}

#[cfg(test)]
mod tests {
use num_traits::FromPrimitive;

use super::*;

#[test]
fn every_parser_node_kind_has_an_ast_kind() {
let first = SyntaxKind::Document as u16;
let end = SyntaxKind::Error as u16;
assert_eq!(AstNodeKind::ALL.len(), usize::from(end - first));

for discriminant in first..end {
let syntax = SyntaxKind::from_u16(discriminant)
.expect("each contiguous parser node discriminant is valid");
let ast = AstNodeKind::try_from(syntax)
.unwrap_or_else(|kind| panic!("missing AST node kind for {kind:?}"));
assert_eq!(SyntaxKind::from(ast), syntax);
}
}

#[test]
fn tokens_trivia_and_sentinels_are_not_ast_node_kinds() {
for kind in [
SyntaxKind::Whitespace,
SyntaxKind::LineComment,
SyntaxKind::Ident,
SyntaxKind::Import,
SyntaxKind::OpenBrace,
SyntaxKind::Plus,
SyntaxKind::Error,
SyntaxKind::Eof,
] {
assert_eq!(AstNodeKind::from_syntax(kind), None);
assert_eq!(AstNodeKind::try_from(kind), Err(kind));
}
}
}
47 changes: 34 additions & 13 deletions crates/rue-compiler/src/std/conditions/types.rue
Original file line number Diff line number Diff line change
Expand Up @@ -193,17 +193,38 @@ export struct Softfork {
...args: List<Any>,
}

export type Condition =
Remark | AggSigParent | AggSigPuzzle | AggSigAmount
| AggSigPuzzleAmount | AggSigParentAmount | AggSigParentPuzzle
| AggSigUnsafe | AggSigMe | CreateCoin | ReserveFee
| CreateCoinAnnouncement | AssertCoinAnnouncement
| CreatePuzzleAnnouncement | AssertPuzzleAnnouncement
| AssertConcurrentSpend | AssertConcurrentPuzzle
| SendMessage | ReceiveMessage | AssertMyCoinId | AssertMyParentId
| AssertMyPuzzleHash | AssertMyAmount | AssertMyBirthSeconds
| AssertMyBirthHeight | AssertEphemeral | AssertSecondsRelative
| AssertSecondsAbsolute | AssertHeightRelative | AssertHeightAbsolute
| AssertBeforeSecondsRelative | AssertBeforeSecondsAbsolute
| AssertBeforeHeightRelative | AssertBeforeHeightAbsolute
export type Condition = Remark
| AggSigParent
| AggSigPuzzle
| AggSigAmount
| AggSigPuzzleAmount
| AggSigParentAmount
| AggSigParentPuzzle
| AggSigUnsafe
| AggSigMe
| CreateCoin
| ReserveFee
| CreateCoinAnnouncement
| AssertCoinAnnouncement
| CreatePuzzleAnnouncement
| AssertPuzzleAnnouncement
| AssertConcurrentSpend
| AssertConcurrentPuzzle
| SendMessage
| ReceiveMessage
| AssertMyCoinId
| AssertMyParentId
| AssertMyPuzzleHash
| AssertMyAmount
| AssertMyBirthSeconds
| AssertMyBirthHeight
| AssertEphemeral
| AssertSecondsRelative
| AssertSecondsAbsolute
| AssertHeightRelative
| AssertHeightAbsolute
| AssertBeforeSecondsRelative
| AssertBeforeSecondsAbsolute
| AssertBeforeHeightRelative
| AssertBeforeHeightAbsolute
| Softfork;
22 changes: 12 additions & 10 deletions crates/rue-compiler/src/std/curry_tree_hash.rue
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@ inline fn two_item_list_hash(first: Bytes32, rest: Bytes32) -> Bytes32 {
}

fn apply_hash(mod_hash: Bytes32, environment_hash: Bytes32) -> Bytes32 {
sha256(2 as Bytes + tree_hash_atom(2 as Bytes) + two_item_list_hash(quote_hash(mod_hash), environment_hash))
sha256(
2 as Bytes
+ tree_hash_atom(2 as Bytes)
+ two_item_list_hash(quote_hash(mod_hash), environment_hash),
)
}

fn update_hash_with_parameter(
parameter_hash: Bytes32,
environment_hash: Bytes32
) -> Bytes32 {
sha256(2 as Bytes + tree_hash_atom(4 as Bytes) + two_item_list_hash(quote_hash(parameter_hash), environment_hash))
fn update_hash_with_parameter(parameter_hash: Bytes32, environment_hash: Bytes32) -> Bytes32 {
sha256(
2 as Bytes
+ tree_hash_atom(4 as Bytes)
+ two_item_list_hash(quote_hash(parameter_hash), environment_hash),
)
}

fn curried_params_hash(parameters: List<Bytes32>) -> Bytes32 {
Expand All @@ -26,9 +31,6 @@ fn curried_params_hash(parameters: List<Bytes32>) -> Bytes32 {
update_hash_with_parameter(parameters.first, curried_params_hash(parameters.rest))
}

export fn curry_tree_hash(
mod_hash: Bytes32,
parameters: List<Bytes32>
) -> Bytes32 {
export fn curry_tree_hash(mod_hash: Bytes32, parameters: List<Bytes32>) -> Bytes32 {
apply_hash(mod_hash, curried_params_hash(parameters))
}
24 changes: 7 additions & 17 deletions crates/rue-compiler/src/std/merkle.rue
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// merkle.rue by yakuhito

import tree_hash::{tree_hash_atom, tree_hash_pair};

export struct MerkleProof {
Expand All @@ -15,7 +14,7 @@ export fn calculate_merkle_root(
if additional_steps is nil {
return current_hash;
}

calculate_merkle_root(
path >>> 1,
tree_hash_pair(
Expand All @@ -28,16 +27,13 @@ export fn calculate_merkle_root(
current_hash
} else {
additional_steps.first
}
},
),
additional_steps.rest
additional_steps.rest,
)
}

fn simplify_merkle_proof_after_leaf(
leaf_hash: Bytes32,
proof: MerkleProof,
) -> Bytes32 {
fn simplify_merkle_proof_after_leaf(leaf_hash: Bytes32, proof: MerkleProof) -> Bytes32 {
if proof.hashes is nil {
return leaf_hash;
}
Expand All @@ -53,18 +49,12 @@ fn simplify_merkle_proof_after_leaf(
leaf_hash
} else {
proof.hashes.first
}
},
),
MerkleProof {
path: proof.path >>> 1,
hashes: proof.hashes.rest
}
MerkleProof { path: proof.path >>> 1, hashes: proof.hashes.rest },
)
}

export inline fn simplify_merkle_proof(
leaf: Bytes32,
proof: MerkleProof,
) -> Bytes32 {
export inline fn simplify_merkle_proof(leaf: Bytes32, proof: MerkleProof) -> Bytes32 {
simplify_merkle_proof_after_leaf(tree_hash_atom(leaf), proof)
}
6 changes: 3 additions & 3 deletions crates/rue-compiler/src/std/prelude.rue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export utils::*;
export tree_hash::*;
export curry_tree_hash::*;
export conditions::message_flags::*;
export conditions::opcodes::*;
export conditions::types::*;
export curry_tree_hash::*;
export merkle::*;
export tree_hash::*;
export utils::*;

export mod std {
export conditions;
Expand Down
26 changes: 26 additions & 0 deletions crates/rue-formatter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "rue-formatter"
version = "0.9.0"
edition = "2024"
license = "Apache-2.0"
description = "An AST formatter for the Rue programming language."
authors = ["Brandon Haggstrom <me@rigidnetwork.com>"]
homepage = "https://github.com/xch-dev/rue"
repository = "https://github.com/xch-dev/rue"
readme = { workspace = true }
keywords = { workspace = true }
categories = { workspace = true }

[lints]
workspace = true

[dependencies]
rue-ast = { workspace = true }
rue-diagnostic = { workspace = true }
rue-lexer = { workspace = true }
rue-parser = { workspace = true }
rowan = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
expect-test = { workspace = true }
Loading
Loading