Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
33 changes: 18 additions & 15 deletions crates/sploosh-parser/tests/corpus.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
use sploosh_parser::parse_program;

/// Parses every `.sp` fixture in `tests/corpus/` at the repo root. Fixtures
/// are discovered, not listed, so a new file cannot be silently skipped
/// (crates/AGENTS.md: corpus tests for every accepted grammar shape).
#[test]
fn parses_corpus_files() {
for path in [
"tests/corpus/basic.sp",
"tests/corpus/actor.sp",
"tests/corpus/control_flow.sp",
"tests/corpus/traits_impls.sp",
"tests/corpus/pipes.sp",
"tests/corpus/send_assign.sp",
"tests/corpus/ranges_modifiers.sp",
] {
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.join(path);
let source = std::fs::read_to_string(&path).unwrap_or_else(|err| {
panic!("{}: {err}", path.display());
});
let corpus_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../tests/corpus");
let mut paths: Vec<_> = std::fs::read_dir(&corpus_dir)
.unwrap_or_else(|err| panic!("{}: {err}", corpus_dir.display()))
.map(|entry| entry.expect("corpus dir entry").path())
.filter(|path| path.extension().is_some_and(|ext| ext == "sp"))
.collect();
paths.sort();
assert!(
!paths.is_empty(),
"no .sp fixtures found in {}",
corpus_dir.display()
);
for path in paths {
let source = std::fs::read_to_string(&path)
.unwrap_or_else(|err| panic!("{}: {err}", path.display()));
parse_program(&source).unwrap_or_else(|errors| panic!("{}: {errors:#?}", path.display()));
}
}
18 changes: 18 additions & 0 deletions tests/corpus/async_await.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// Async functions, `.await`, and `?` error propagation outside pipes
/// (§6 errors, §8.9 async). `.context(...)` is an ordinary method call.
async fn fetch(url: &str) -> Result<Response, NetError> {
let response = net::get(url).await?;
Ok(response)
}

pub async fn retry(url: &str) -> Result<Response, NetError> {
let first = fetch(url).await;
let second = fetch(url).await?;
Ok(second)
}

fn propagate(input: &str) -> Result<i64, ParseError> {
let n = parse::<i64>(input)?;
let checked = validate(n).context("validating input")?;
Ok(checked)
}
41 changes: 41 additions & 0 deletions tests/corpus/attributes.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/// Attribute shapes (§12, §16 attrs/attr_args): bare markers, derive lists,
/// named arguments, and actor-handler attributes.
@derive(Serialize, Clone, Debug)
struct Payload {
pub body: String,
}

@error
enum AppError {
NotFound,
Denied,
}

@overflow(wrapping)
fn wrap_add(a: u8, b: u8) -> u8 {
a + b
}

@fast_math(contract, afn)
fn mix(a: f64, b: f64) -> f64 {
a * b + a
}

@supervisor(strategy: "one_for_one", max_restarts: 5, window_secs: 60)
actor Sup {
children: i64,
}

actor Mailer {
queued: i64,

@mailbox(capacity: 2048)
pub fn enqueue(&mut self, n: i64) {
self.queued = self.queued + n;
}
}

@test
fn smoke() {
let ok = true;
}
35 changes: 35 additions & 0 deletions tests/corpus/casts_literals.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/// Numeric casts (§3.2 `as`, numeric-only) and the §16.1 literal zoo: based
/// integers, separators, suffixes, float exponents, string escapes, and
/// character literals. Lifetimes appear in generic params and reference types.
fn convert(n: i64, ratio: f64) -> u32 {
let small = n as i32;
let wide = small as i64;
let scaled = ratio as f32;
let back = scaled as f64;
let total = wide + n;
total as u32
}

fn literals() -> f64 {
let hex = 0xFF_FFu32;
let oct = 0o777;
let bin = 0b1010_1010u8;
let million = 1_000_000;
let big = 340_282_366_920_938u128;
let chain_cap = 115_792u256;
let pi = 3.14159f64;
let tiny = 2.5e-3;
let large = 1e10f64;
let greeting = "hi\n\t\\\"\x41\u{1F600}";
let letter = 'a';
let newline = '\n';
let quote = '\'';
let escaped = '\u{41}';
let yes = true;
let no = false;
3.0
}

fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
a
}
34 changes: 34 additions & 0 deletions tests/corpus/expressions.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// Struct literals (§5.1 incl. the parenthesized block-head escape and
/// shorthand field init), nesting, and the boolean/comparison operator set.
struct Point {
pub x: i64,
pub y: i64,
}

struct Cfg {
pub on: bool,
}

fn build(x: i64, y: i64) -> Point {
let origin = Point { x: 0, y: 0 };
let shorthand = Point { x, y };
let nested = Wrap { inner: Point { x: 1, y: 2 } };
origin
}

fn guarded() -> i64 {
if (Cfg { on: true }).on {
1
} else {
2
}
}

fn logic(a: bool, b: bool, lo: i64, hi: i64) -> bool {
let both = a && b;
let either = a || b;
let cmp = lo <= hi;
let ne = lo != hi;
let modulo = hi % 7 == 0;
both && either && cmp && ne && modulo
}
34 changes: 34 additions & 0 deletions tests/corpus/extern_onchain.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// FFI and on-chain surfaces: extern "C" blocks (§4.9), string-target async
/// extern blocks, extern onchain mod declarations (§11.4a), a top-level
/// onchain enum, and an onchain mod with a storage block (§11.1a).
extern "C" {
pub fn puts(s: &str) -> i32;
fn c_open(path: &str, flags: i32) -> Result<i32, FfiError>;
}

extern "C" async {
fn poll_events(mask: u32) -> u64;
}

extern onchain mod token {
pub fn balance_of(account: Address) -> Result<u256, TokenError>;
}

onchain enum TokenError {
InsufficientBalance,
Unauthorized,
}

onchain mod vault {
storage {
balances: Map<Address, u256>,
supply: u256,
}

pub fn deposit(amount: u256) -> Result<u256, TokenError> {
let caller = ctx::caller();
let current = storage::get(&self.balances, caller)?;
storage::set(&mut self.balances, caller, current + amount);
Ok(current + amount)
}
}
23 changes: 23 additions & 0 deletions tests/corpus/modules_use.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// Module trees and use declarations (§10): inline modules, file modules,
/// nested paths, brace imports, contextual `crate`/`super` heads, and
/// re-exports.
mod auth {
pub mod login;
pub mod token;

pub fn is_enabled() -> bool {
true
}
}

mod models;

use std::collections::Map;
use crate::models::{User, Role};
pub use crate::models::User;
use super::shared;
use crate::api;

fn wire() -> bool {
true
}