a new AST module

This commit is contained in:
sevki 2024-07-15 00:01:54 +01:00
parent c8f3be4df8
commit cb4733b61d
32 changed files with 230317 additions and 14991 deletions

View file

@ -1,6 +1,7 @@
ARG VARIANT "bookworm-20240612"
ARG VARIANT "bookworm-20240701"
FROM debian:${VARIANT}
# FROM debian:${VARIANT}
FROM debian:bookworm-20240701
RUN apt-get update && apt-get install -y \
sudo \

View file

@ -3,7 +3,8 @@
"build": {
"dockerfile": "Dockerfile",
"args": {
"VARIANT": "bookworm-20240612", }
"VARIANT": "bookworm-20240701"
}
},
"runArgs": [
"--device=/dev/kvm",

View file

@ -21,20 +21,14 @@ on:
jobs:
rust-clippy-analyze:
name: Run rust-clippy analyzing
runs-on: self-hosted
permissions:
contents: read
security-events: write
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
steps:
- name: Modify hosts file
run: |
echo "66.241.125.220 ok.software" >> /etc/hosts
- name: Checkout code
uses: actions/checkout@v2
- name: Install Rust toolchain
uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af #@v1
with:
@ -42,10 +36,8 @@ jobs:
toolchain: stable
components: clippy
override: true
- name: Install required cargo
run: cargo install clippy-sarif sarif-fmt
- name: Run rust-clippy
run:
cargo clippy
@ -57,4 +49,4 @@ jobs:
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: rust-clippy-results.sarif
wait-for-processing: true
wait-for-processing: true

View file

@ -8,6 +8,8 @@ on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]
pull_request:
branches: ["main"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
@ -29,6 +31,14 @@ jobs:
build:
runs-on: ubuntu-latest
container: ghcr.io/sevki/devcontainer:main
strategy:
matrix:
targets: [
x86_64-unknown-linux-gnu
]
packages: [srclang]
toolchains: [stable]
env:
MDBOOK_VERSION: 0.4.40
steps:
@ -38,7 +48,7 @@ jobs:
rustup toolchain install ${{ matrix.toolchains }}
rustup component add cargo
rustup component add clippy
rustup component add rust-src
rustup component add rust-src
rustup target add ${{ matrix.targets }}
rustup update
- name: Install mdBook
@ -65,6 +75,7 @@ jobs:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
needs: build
steps:
- name: Deploy to GitHub Pages

41
.github/workflows/rust-linux.yml vendored Normal file
View file

@ -0,0 +1,41 @@
name: Rust
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
env:
MDBOOK_VERSION: 0.4.40
runs-on: ubuntu-latest
container: ghcr.io/sevki/devcontainer:main
strategy:
matrix:
targets:
- x86_64-unknown-linux-gnu
packages:
- srclang
toolchains:
- stable
- nightly
steps:
- uses: actions/checkout@v4
- name: rustup update
run: |
rustup toolchain install ${{ matrix.toolchains }}
rustup component add cargo
rustup component add clippy
rustup component add rust-src
rustup target add ${{ matrix.targets }}
rustup update
- name: Build ${{ matrix.packages }} for ${{ matrix.targets }}
run: cargo build --verbose --target ${{ matrix.targets }} -p ${{ matrix.packages }}
- name: Test ${{ matrix.packages }} for ${{ matrix.targets }}
run: cargo test --verbose --target ${{ matrix.targets }} -p ${{ matrix.packages }}

View file

@ -1,61 +0,0 @@
name: Rust
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
env:
MDBOOK_VERSION: 0.4.40
runs-on: ubuntu-latest
container: ghcr.io/sevki/devcontainer:main
strategy:
matrix:
targets: [
wasm32-unknown-unknown
# , x86_64-unknown-linux-gnu
]
packages: [srclang
# ,src-lsp-server, src-lsp-browser
]
toolchains: [stable
# , nightly
]
steps:
- uses: actions/checkout@v4
- name: rustup update
run: |
rustup toolchain install ${{ matrix.toolchains }}
rustup component add cargo
rustup component add clippy
rustup component add rust-src
rustup target add ${{ matrix.targets }}
rustup update
# - name: Build ${{ matrix.packages }} for ${{ matrix.targets }}
# run: cargo build --verbose --target ${{ matrix.targets }} -p ${{ matrix.packages }}
# - name: Test ${{ matrix.packages }} for ${{ matrix.targets }}
# run: cargo test --verbose --target ${{ matrix.targets }} -p ${{ matrix.packages }}
- name: Install mdBook
run: |
cargo install --version ${MDBOOK_VERSION} mdbook
- name: Setup Pages
id: pages
uses: actions/configure-pages@v5
- name: install deps
run: |
cargo install mdbook-svgbob@0.2.0
cargo install mdbook-alerts
- name: Build with mdBook
run: mdbook build
- name: Build the ide
run: |
cd packages/app
npm install
npm run build

8
Cargo.lock generated
View file

@ -973,6 +973,12 @@ dependencies = [
"windows-targets 0.52.5",
]
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "percent-encoding"
version = "2.3.1"
@ -1515,11 +1521,13 @@ dependencies = [
"lalrpop",
"lalrpop-util",
"okstd",
"paste",
"phf_codegen",
"proptest",
"ropey",
"salsa-2022",
"salsa-2022-macros",
"src-derive",
"syn 2.0.66",
"tiny-keccak",
]

View file

@ -5,7 +5,9 @@ edition = "2021"
[workspace]
members = [
"crates/src-collections", "crates/src-derive", "crates/src-derive-test",
"crates/src-collections",
"crates/src-derive",
"crates/src-derive-test",
"crates/src-lsp-browser",
"crates/src-lsp-server",
]
@ -32,6 +34,8 @@ syn = "2.0.60"
bitflags = "2.5.0"
ropey = { version = "1.6.1", features = ["small_chunks"] }
hashbrown = "0.14.5"
src-derive = { version = "0.1.0", path = "crates/src-derive", registry = "oksoftware" }
paste = "1.0.15"
[dev-dependencies]
insta = "1.38.0"

View file

@ -9,3 +9,7 @@ okstd = { version = "0.1.9", registry = "oksoftware", features = ["macros"] }
src-derive = { version = "0.1.0", path = "../src-derive", registry = "oksoftware" }
srclang = { version = "0.1.0", path = "../..", registry = "oksoftware" }
# [[bin]]
# name = "src-derive-test"
# path = "expanded.rs"

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,33 @@
fn main() {
println!("Hello, world!");
use src_derive::node;
use srclang::lexer::Location;
use srclang::ops;
use srclang::parser::span::Spanned;
use srclang::span;
use std::fmt::Display;
use std::ops::Range;
#[node]
struct Ident {
name: String,
generics: Vec<Ident>,
}
use okstd::prelude::*;
use src_derive::visitor;
use srclang::{lexer::Location, Db};
use std::{fmt::Display, ops::Range};
pub const ANON_FN_NAME: &str = "anonymous";
use srclang::parser::span::*;
#[derive(PartialEq, Debug, Clone)]
pub struct Ident(pub String, pub Option<Vec<Spanned<Ident>>>);
impl Display for Ident {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
#[node]
struct Field {
vis: Option<Visibility>,
name: String,
ty: Ident,
}
#[derive(PartialEq, Debug, Clone, Default)]
pub enum Literal {
Bool(bool),
Float(f64),
Integer(i64),
String(String),
}
#[derive(Debug)]
pub enum Visibility {
#[default]
Private,
Public,
}
@ -33,329 +41,79 @@ impl Display for Visibility {
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct StringLit(pub String);
#[derive(PartialEq, Debug, Clone)]
pub struct Binding(pub Spanned<Ident>, pub Box<Spanned<Node>>);
#[derive(PartialEq, Debug, Clone)]
pub enum Literal {
Bool(bool),
Float(f64),
Integer(i64),
String(String),
}
#[derive(PartialEq, Debug, Clone)]
pub enum Keyword {
None,
Some,
Let,
Public,
Private,
Fn,
If,
Else,
Match,
Arrow,
Struct,
SelfValue,
When,
Effect,
Impl,
Use,
From,
Where,
Self_,
}
impl Display for Keyword {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let kw = match self {
Keyword::None => "none",
Keyword::Some => "some",
Keyword::Let => "let",
Keyword::Fn => "fn",
Keyword::If => "if",
Keyword::Else => "else",
Keyword::Match => "match",
Keyword::Arrow => "=>",
Keyword::Struct => "struct",
Keyword::SelfValue => "self",
Keyword::When => "when",
Keyword::Effect => "effect",
Keyword::Impl => "impl",
Keyword::Use => "use",
Keyword::From => "from",
Keyword::Where => "where",
Keyword::Self_ => "Self",
Keyword::Public => "pub",
Keyword::Private => "priv",
};
write!(f, "{}", kw)
}
}
#[derive(PartialEq, Debug, Clone)]
pub enum Value {
Literal(Literal),
Ident(Ident),
}
#[derive(PartialEq, Debug, Clone)]
pub struct Block<T>(pub Vec<T>);
#[derive(PartialEq, Debug, Clone)]
pub struct Tuple<T>(pub Vec<T>);
#[derive(PartialEq, Debug, Clone)]
pub struct Array<T>(pub Vec<T>);
#[derive(PartialEq, Debug, Clone)]
pub struct BinaryOperation {
pub lhs: Box<Spanned<Node>>,
pub op: Operator,
pub rhs: Box<Spanned<Node>>,
}
#[derive(PartialEq, Debug, Clone)]
pub struct FnCall(pub Spanned<Ident>, pub Vec<Spanned<Node>>);
#[derive(PartialEq, Debug, Clone)]
pub enum Node {
BinaryExpression(BinaryOperation),
Bool(bool),
Integer(i64),
Float(f64),
Ident(Spanned<Ident>),
Binding(Binding),
FnCall(FnCall),
String(String),
FnDef(FnDef),
EffectDef(EffectDef),
StructDef(StructDef),
UseDef(UseDef),
Keyword(Keyword),
ImplDef(ImplDef),
Branch(BranchDef),
FieldAccess(FieldAccess),
Visibility(Visibility),
Error,
}
impl Display for Node {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Node::BinaryExpression(bin) => write!(f, "{} {} {}", bin.lhs, bin.op, bin.rhs),
Node::Bool(b) => write!(f, "{}", b),
Node::Integer(i) => write!(f, "{}", i),
Node::Float(fl) => write!(f, "{}", fl),
Node::Ident(ident) => write!(f, "{}", ident.1),
Node::Binding(bind) => write!(f, "{} = {}", bind.0, bind.1),
Node::FnCall(call) => write!(
f,
"{}({})",
call.0,
call.1
.iter()
.map(|e| e.1.to_string())
.collect::<Vec<String>>()
.join(", ")
),
Node::String(s) => write!(f, "{}", s),
Node::FnDef(def) => write!(f, "{}", def.0),
Node::EffectDef(def) => write!(f, "{}", def.0),
Node::StructDef(def) => write!(f, "{}", def.0),
Node::UseDef(def) => write!(f, "{:#?}", def.0),
Node::Keyword(kw) => write!(f, "{}", kw),
Node::ImplDef(def) => write!(f, "{}", def.0),
Node::Branch(branch) => write!(f, "{}", branch.0),
Node::FieldAccess(access) => write!(f, "{}.{}", access.0, access.1),
Node::Visibility(vis) => write!(f, "{}", vis),
Node::Error => write!(f, "Error"),
}
}
}
#[derive(PartialEq, Debug, Clone)]
pub enum FnArg {
Reciever,
Field(Spanned<FieldDef>),
}
impl Display for FnArg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FnArg::Reciever => write!(f, "self"),
FnArg::Field(field) => write!(f, "{}", field.1),
}
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct Prototype {
pub name: Spanned<Ident>,
pub args: Vec<Spanned<FnArg>>,
pub ret: Option<Spanned<Ident>>,
pub effects: Vec<Spanned<Ident>>,
}
impl Display for Prototype {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}(", self.name)?;
for arg in self.args.iter() {
write!(f, "{}", arg)?;
}
write!(f, ")")?;
if let Some(ret) = &self.ret {
write!(f, " -> {}", ret)?;
}
Ok(())
}
}
#[derive(PartialEq, Debug, Clone)]
pub enum Whitespace {
Space,
Tab,
Newline,
}
#[derive(PartialEq, Debug, Clone)]
pub enum Operator {
Add,
Sub,
Mul,
Div,
Modulo,
Increment,
Decrement,
Maybe,
Mod,
And,
Or,
Not,
Neg,
Dot,
Arrow,
FatArrow,
DoubleColon,
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
impl Display for Operator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let op = match self {
Operator::Add => "+",
Operator::Sub => "-",
Operator::Mul => "*",
Operator::Div => "/",
Operator::Modulo => "%",
Operator::Increment => "++",
Operator::Decrement => "--",
Operator::Maybe => "?",
Operator::Not => "!",
Operator::Neg => "-",
Operator::Dot => ".",
Operator::Arrow => "->",
Operator::FatArrow => "=>",
Operator::DoubleColon => "::",
};
write!(f, "{}", op)
struct PrettyPrinter;
impl FieldVisitor for PrettyPrinter {
fn visit_vis(&self, vis: &Visibility, range: &Range<Location>) -> ops::traversal::Result {
print!("{} ", vis);
ops::traversal::Result::Continue
}
fn visit_name(&self, name: &String, range: &Range<Location>) -> ops::traversal::Result {
print!("{} :", name);
ops::traversal::Result::Continue
}
fn visit_ty(&self, ty: &Ident, range: &Range<Location>) -> ops::traversal::Result {
ty.accept(self);
ops::traversal::Result::Continue
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct FieldAccess(pub Box<Spanned<Node>>, pub Box<Spanned<Node>>);
impl IdentVisitor for PrettyPrinter {
fn visit_name(&self, name: &String, range: &Range<Location>) -> ops::traversal::Result {
print!("{}", name);
ops::traversal::Result::Continue
}
#[derive(PartialEq, Debug, Clone)]
pub struct Module(pub Vec<Spanned<Node>>);
// defs
#[derive(PartialEq, Debug, Clone)]
pub struct FieldDef(
pub Spanned<Visibility>,
pub Spanned<Ident>,
pub Spanned<Ident>,
);
impl Display for FieldDef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", self.0, self.1)
fn visit_generics(&self, generic: &Ident, range: &Range<Location>) -> ops::traversal::Result {
print!("<");
generic.accept(self);
print!(">");
ops::traversal::Result::Continue
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct StructDef(
pub KeywordAndVisibility,
pub Spanned<Ident>,
pub Block<Spanned<FieldDef>>,
);
fn main() {
let b = Ident::new(
span!(Location::default(), "b".to_string(), Location::default()),
vec![span!(
Location::default(),
Ident::new(
span!(Location::default(), "c".to_string(), Location::default()),
vec![]
),
Location::default()
)],
);
let a = Field::new(
Some(span!(
Location::default(),
Visibility::Public,
Location::default()
)),
span!(Location::default(), "a".to_string(), Location::default()),
span!(Location::default(), b, Location::default()),
);
#[derive(PartialEq, Debug, Clone)]
pub struct FnIdent(pub Ident);
#[derive(PartialEq, Debug, Clone)]
pub struct EffectDef(
pub KeywordAndVisibility,
pub Spanned<Ident>,
pub Vec<Spanned<Ident>>,
pub Block<Spanned<Prototype>>,
);
#[derive(PartialEq, Debug, Clone)]
pub struct UseDef(
pub KeywordAndVisibility,
pub Vec<Spanned<Ident>>,
pub Spanned<Ident>,
);
impl Display for UseDef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {:?} from {}", self.0, self.1, self.2)
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct KeywordAndVisibility(pub Spanned<Keyword>, pub Spanned<Visibility>);
impl Display for KeywordAndVisibility {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}", self.1, self.0)
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct ImplDef(
pub KeywordAndVisibility,
pub Spanned<Ident>,
pub Option<Spanned<Ident>>,
pub Block<Spanned<Node>>,
);
#[derive(PartialEq, Debug, Clone)]
pub struct BranchDef(
pub Box<Spanned<Node>>,
pub Vec<(Spanned<Node>, Block<Spanned<Node>>)>,
);
#[derive(PartialEq, Debug, Clone)]
pub struct FnDef(
pub KeywordAndVisibility,
pub Spanned<Prototype>,
pub Block<Spanned<Node>>,
pub Vec<(Spanned<Ident>, Block<Spanned<Node>>)>,
);
impl Display for FnDef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {} {{", self.0, self.1)?;
for expr in self.2 .0.iter() {
write!(f, "{}", expr)?;
}
write!(f, "}}")
}
}
trait Visitor {
fn visit_module(&mut self, module: &Module, span: Range<Location>);
fn visit_block(&mut self, block: &Block<Spanned<Node>>, span: Range<Location>);
let pretty_printer = PrettyPrinter;
a.accept(&pretty_printer);
println!("");
}

View file

@ -1,8 +1,13 @@
use proc_macro::TokenStream;
mod visitor;
mod node;
mod walker;
#[proc_macro_attribute]
pub fn visitor(_attr: TokenStream, item: TokenStream) -> TokenStream {
TokenStream::from(visitor::generate_visitor_trait(item))
pub fn node(_attr: TokenStream, item: TokenStream) -> TokenStream {
TokenStream::from(node::define_nodes(_attr, item))
}
#[proc_macro_attribute]
pub fn walker(_attr: TokenStream, item: TokenStream) -> TokenStream {
TokenStream::from(walker::generate_walker_impl(item))
}

View file

@ -0,0 +1,346 @@
use proc_macro::TokenStream;
use quote::{format_ident, quote, ToTokens};
use syn::{
parse_macro_input, Data, DeriveInput, Fields, GenericArgument, Ident, PathArguments, Type,
TypePath,
};
pub fn define_nodes(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let struct_name = &input.ident;
let fields = match &input.data {
Data::Struct(data) => &data.fields,
_ => {
return quote! {
compile_error!("define_nodes can only be used on structs");
}
.into()
}
};
let spanned_fields = fields.iter().map(|field| {
let field_name = &field.ident;
let field_type = &field.ty;
match field_type {
Type::Path(path) => {
let expanded_type = wrap_path_in_spanned(path);
quote! {
#field_name: #expanded_type,
}
}
_ => {
panic!(
"Only named fields are supported which {} is not",
field_type.into_token_stream()
);
}
}
});
let expanded_impl = fields.iter().map(|field| {
let field_name = &field.ident;
let field_span_getter = format_ident!("{}_span", field_name.as_ref().unwrap());
let field_node_getter = format_ident!("{}_node", field_name.as_ref().unwrap());
let field_type = &field.ty;
match field_type {
Type::Path(path) => {
let expanded_type = wrap_path_in_spanned(path);
let expanded_range_type = wrap_range_location(path);
quote! {
fn #field_node_getter(&self) -> &#expanded_type {
todo!()
}
fn #field_span_getter(&self) -> &#expanded_range_type {
todo!()
}
}
}
_ => {
panic!(
"Only named fields are supported which {} is not",
field_type.into_token_stream()
);
}
}
});
let visitor_name = format_ident!("{}Visitor", struct_name);
let visitor_trait_stub = fields.iter().map(|field| {
let field_name = &field.ident;
let field_visit = format_ident!("visit_{}", field_name.as_ref().unwrap());
let field_type = &field.ty;
match field_type {
Type::Path(path) => {
let unwrapped_type = unwrap_path(path);
quote! {
fn #field_visit(&self, node: &#unwrapped_type, span: &Range<Location>) -> ops::traversal::Result;
}
}
_ => {
panic!(
"Only named fields are supported which {} is not",
field_type.into_token_stream()
);
}
}
});
let accept_impl = fields.iter().map(|field| {
let field_name = &field.ident;
let field_type = &field.ty;
match field_type {
Type::Path(path) => {
let visit_fn = format_ident!("visit_{}", field_name.as_ref().unwrap());
match path.path.segments.last() {
Some(syn::PathSegment { ident, arguments }) => match arguments {
PathArguments::None => {
quote! {
if let cont = visitor.#visit_fn(
&self.#field_name.1,
&(self.#field_name.0..self.#field_name.2)
) {
return;
}
}
}
PathArguments::AngleBracketed(args) => match args.args.first() {
Some(GenericArgument::Type(_)) => match ident.to_string().as_str() {
"Option" => {
quote! {
if let Some(inner) = &self.#field_name {
if let cont = visitor.#visit_fn(
&inner.1,
&(inner.0..inner.2)
) {
return;
}
}
}
}
"Vec" => {
quote! {
for inner in self.#field_name.iter() {
if let cont = visitor.#visit_fn(
&inner.1,
&(inner.0..inner.2)
) {
return;
}
}
}
}
_ => {
quote! {
if let cont =visitor.#visit_fn(
&self.#field_name.1,
&(self.#field_name.0..self.#field_name.2)
) {
return;
}
}
}
},
_ => {
quote! {
if let cont = visitor.#visit_fn(
self.1,
self.0..self.2
) {
return;
}
}
}
},
PathArguments::Parenthesized(_) => todo!(),
},
None => {
quote! {
compile_error!("No path segments found");
}
}
}
}
_ => {
panic!(
"Only named fields are supported which {} is not",
field_type.into_token_stream()
);
}
}
});
let field_names = fields.iter().map(|field| {
let field_name = &field.ident;
quote! {
#field_name
}
});
let not_spanned_fileds = spanned_fields.clone();
let field_types = fields.iter().map(|field| {
let field_type = &field.ty;
match field_type {
Type::Path(path) => {
let expanded_type = wrap_path_in_spanned(path);
quote! {
#expanded_type
}
}
_ => {
panic!(
"Only named fields are supported which {} is not",
field_type.into_token_stream()
);
}
}
});
let field_types_clone = field_types.clone();
let struct_name_lower = format_ident!("{}", struct_name.to_string().to_lowercase());
let field_ids = fields.iter().enumerate().map(|field| {
let field_name = syn::Index::from(field.0);
quote! {
#struct_name_lower.#field_name
}
});
let vis = &input.vis;
let expanded = quote! {
#[derive(Debug)]
#vis struct #struct_name {
#(#spanned_fields)*
}
#vis trait #visitor_name {
#(#visitor_trait_stub)*
}
impl From<
(#(#field_types),*)
> for #struct_name {
fn from(
#struct_name_lower: (
#(#field_types_clone),*
)
) -> Self {
Self::new(
#(#field_ids),*
)
}
}
impl #struct_name {
fn new(#(#not_spanned_fileds)*) -> Self {
Self {
#(#field_names,)*
}
}
}
impl #struct_name {
fn accept(&self, visitor: &impl #visitor_name) {
#(#accept_impl)*
}
}
};
expanded.into()
}
fn wrap_range_location(path: &TypePath) -> impl ToTokens {
match path.path.segments.last() {
Some(syn::PathSegment { ident, arguments }) => {
if let syn::PathArguments::AngleBracketed(args) = arguments {
if let Some(GenericArgument::Type(inner_ty)) = args.args.first() {
quote! {
#ident<Range<Location>>
}
} else {
quote! {
Range<Location>
}
}
} else {
quote! {
Range<Location>
}
}
}
_ => {
quote! {
Range<Location>
}
}
}
}
fn wrap_path_in_spanned(path: &TypePath) -> impl ToTokens {
match path.path.segments.last() {
Some(syn::PathSegment { ident, arguments }) => {
if let syn::PathArguments::AngleBracketed(args) = arguments {
if let Some(GenericArgument::Type(inner_ty)) = args.args.first() {
quote! {
#ident<Spanned<#inner_ty>>
}
} else {
quote! {
Spanned<#ident>
}
}
} else {
quote! {
Spanned<#ident>
}
}
}
_ => {
quote! {
Spanned<#path>
}
}
}
}
fn unwrap_path(path: &TypePath) -> impl ToTokens {
match path.path.segments.last() {
Some(syn::PathSegment { ident, arguments }) => {
if let syn::PathArguments::AngleBracketed(args) = arguments {
if let Some(GenericArgument::Type(inner_ty)) = args.args.first() {
quote! {
#inner_ty
}
} else {
quote! {
#ident
}
}
} else {
quote! {
#ident
}
}
}
_ => {
quote! {
#path
}
}
}
}
fn wrap_type_in_spanned(ty: &Type, field_name: &Option<Ident>) -> impl ToTokens {
match (ty, field_name) {
(Type::Path(path), Some(field_name)) => {
let ty = wrap_path_in_spanned(path);
quote! {
#field_name: #ty,
}
}
(Type::Path(path), None) => {
let ty = wrap_path_in_spanned(path);
quote! {
#ty,
}
}
_ => {
quote! {
compile_error!("Only named fields are supported");
}
}
}
}

View file

@ -1,6 +1,5 @@
---
source: crates/src-derive/src/lib.rs
assertion_line: 157
expression: expected.to_string()
---
pub trait BinaryOperationVisitor : BoxVisitor + SpannedVisitor + NodeVisitor + OperatorVisitor { fn visit (& mut self , node : & BinaryOperation) { self . visit_lhs (& node . lhs) ; self . visit_op (& node . op) ; self . visit_rhs (& node . rhs) ; } fn visit_lhs (& mut self , value : & Box < Spanned < Node >>) { } fn visit_op (& mut self , value : & Operator) { } fn visit_rhs (& mut self , value : & Box < Spanned < Node >>) { } }

View file

@ -1,83 +0,0 @@
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, DeriveInput, Data, Fields};
pub fn generate_visitor_trait(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let item = proc_macro::TokenStream::from(stream);
let input = parse_macro_input!(item as DeriveInput);
let struct_name = input.ident;
let visitor_trait_name = format_ident!("{}Visitor", struct_name);
let field_types: Vec<syn::Type> = match input.data {
Data::Struct(data_struct) => match data_struct.fields {
Fields::Named(fields) => fields.named.into_iter().map(|field| field.ty).collect(),
Fields::Unnamed(fields) => fields.unnamed.into_iter().map(|field| field.ty).collect(),
Fields::Unit => vec![],
},
_ => panic!("visitor macro only supports structs"),
};
let field_visitor_traits = field_types.iter().map(|ty| {
let ty_str = quote!(#ty).to_string();
let visitor_trait_name = format_ident!("{}Visitor", ty_str);
quote! { + #visitor_trait_name }
});
let visitor_methods = field_types.iter().map(|ty| {
let ty_str = quote!(#ty).to_string();
let method_name = format_ident!("visit_{}", ty_str);
quote! {
fn #method_name(self, node: #ty, span: Range<Location>);
}
});
let expanded = quote! {
trait #visitor_trait_name: NodeVisitor #(#field_visitor_traits)* {
#(#visitor_methods)*
}
};
proc_macro::TokenStream::from(expanded)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_visitor() {
let input = quote! {
#[visitor]
pub struct Test {
field1: Spanned<Ident>,
field2: Option<Spanned<Ident>>,
field3: Box<Spanned<Ident>>,
field4: Vec<Spanned<Ident>>,
field5: Block<Spanned<Ident>>,
}
};
let expected = quote! {
pub trait TestVisitor {
fn visit_ident_field(&mut self, value: Ident, span: &Span);
fn visit_ident_field2(&mut self, value: Option<Ident>, span: &Span);
fn visit_ident_field3(&mut self, value: Ident, span: &Span);
fn visit_ident_field4(&mut self, value: Vec<Ident>, span: &Span);
fn visit_ident_field5(&mut self, value: Block<Ident>, span: &Span);
}
pub struct Test {
field1: Spanned<Ident>,
field2: Option<Spanned<Ident>>,
field3: Box<Spanned<Ident>>,
field4: Vec<Spanned<Ident>>,
field5: Block<Spanned<Ident>>,
}
};
let actual = visitor(TokenStream::new(), input).to_string();
assert_eq!(expected.to_string(), actual);
}
}

View file

@ -0,0 +1,179 @@
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote, ToTokens};
use syn::{
parse_macro_input, Data, DeriveInput, Fields, GenericArgument, PathArguments, Type, TypePath,
};
pub fn generate_walker_impl(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let type_name = &input.ident;
let walker_name = format_ident!("{}Walker", type_name);
let visitor_name = format_ident!("{}Visitor", type_name);
let walk_impl = generate_walk_impl(type_name, &input.data);
let expanded = quote! {
#input
pub struct #walker_name;
impl #walker_name {
pub fn walk<V: #visitor_name>(node: &Spanned<#type_name>, visitor: &mut V) {
#walk_impl
}
}
};
proc_macro::TokenStream::from(expanded)
}
fn generate_walk_impl(type_name: &Ident, data: &Data) -> TokenStream {
match data {
Data::Struct(data_struct) => generate_struct_walk_impl(data_struct),
Data::Enum(data_enum) => generate_enum_walk_impl(type_name, data_enum),
Data::Union(_) => panic!("Unions are not supported"),
}
}
fn generate_field_visit(ty: &Type, field_access: TokenStream) -> TokenStream {
match ty {
Type::Path(TypePath { path, .. }) => {
if let Some(segment) = path.segments.last() {
match segment.ident.to_string().as_str() {
"Spanned" => {
if let PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(GenericArgument::Type(inner_type)) = args.args.first() {
let visit_method = format_ident!(
"visit_{}",
inner_type.to_token_stream().to_string().to_lowercase()
);
return quote! {
visitor.#visit_method(&(#field_access).1, (#field_access).span());
};
}
}
}
"Box" => {
if let PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(GenericArgument::Type(inner_type)) = args.args.first() {
let inner_visit =
generate_field_visit(inner_type, quote! { (*#field_access) });
return quote! {
#inner_visit
};
}
}
}
"Option" => {
if let PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(GenericArgument::Type(inner_type)) = args.args.first() {
let inner_visit =
generate_field_visit(inner_type, quote! { inner });
return quote! {
if let Some(inner) = #field_access.as_ref() {
#inner_visit
}
};
}
}
}
"Vec" => {
if let PathArguments::AngleBracketed(args) = &segment.arguments {
if let Some(GenericArgument::Type(inner_type)) = args.args.first() {
let inner_visit = generate_field_visit(inner_type, quote! { item });
return quote! {
for item in #field_access.iter() {
#inner_visit
}
};
}
}
}
_ => {}
}
}
}
_ => {}
}
quote! {}
}
fn generate_struct_walk_impl(data_struct: &syn::DataStruct) -> TokenStream {
let field_visits = data_struct
.fields
.iter()
.map(|field| {
let field_name = &field.ident;
generate_field_visit(&field.ty, quote!(node.1.#field_name))
})
.collect::<Vec<_>>();
quote! {
#(#field_visits)*
}
}
fn generate_enum_walk_impl(enum_name: &Ident, data_enum: &syn::DataEnum) -> TokenStream {
let variant_matches = data_enum
.variants
.iter()
.map(|variant| {
let variant_name = &variant.ident;
match &variant.fields {
Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
let field_visit = generate_field_visit(&fields.unnamed[0].ty, quote!(value));
quote! {
#enum_name::#variant_name(value) => {
#field_visit
}
}
}
_ => quote! {
#enum_name::#variant_name { .. } => {}
},
}
})
.collect::<Vec<_>>();
quote! {
match &node.1 {
#(#variant_matches)*
}
}
}
fn is_spanned_type(ty: &Type) -> bool {
if let Type::Path(TypePath { path, .. }) = ty {
if let Some(segment) = path.segments.last() {
return segment.ident == "Spanned";
}
}
false
}
fn is_box_type(ty: &Type) -> bool {
if let Type::Path(TypePath { path, .. }) = ty {
if let Some(segment) = path.segments.last() {
return segment.ident == "Box";
}
}
false
}
fn is_option_type(ty: &Type) -> bool {
if let Type::Path(TypePath { path, .. }) = ty {
if let Some(segment) = path.segments.last() {
return segment.ident == "Option";
}
}
false
}
fn is_vec_type(ty: &Type) -> bool {
if let Type::Path(TypePath { path, .. }) = ty {
if let Some(segment) = path.segments.last() {
return segment.ident == "Vec";
}
}
false
}

72390
expanded.ast.rs Normal file

File diff suppressed because it is too large Load diff

72292
src/ast/expanded.ast.rs Normal file

File diff suppressed because it is too large Load diff

72293
src/ast/expanded.rs Normal file

File diff suppressed because it is too large Load diff

71
src/ast/mod.rs Normal file
View file

@ -0,0 +1,71 @@
use crate::lexer::Location;
use crate::ops;
use crate::parser::span::Spanned;
use src_derive::node;
use std::fmt::Display;
use std::ops::Range;
/// ast node representing an identifier.
#[node]
pub struct Ident {
name: String,
generics: Vec<Ident>,
}
/// ast node representing a field.
#[node]
pub struct Field {
vis: Option<Visibility>,
name: String,
ty: Ident,
}
/// An enum representing the different types of literals that can be used in an expression.
pub enum Literal {
Bool(bool),
Float(f64),
Integer(i64),
String(String),
}
#[derive(Debug)]
/// An enum representing the visibility of a field or method.
pub enum Visibility {
Private,
Public,
}
impl Display for Visibility {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Visibility::Public => write!(f, "pub"),
Visibility::Private => write!(f, "priv"),
}
}
}
/// An enum representing the different operators that can be used in an expression.
pub enum Operator {
Add,
Sub,
Mul,
Div,
Mod,
And,
Or,
Not,
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
pub enum Node {
Ident(Ident),
Field(Field),
Literal(Literal),
Visibility(Visibility),
Operator(Operator),
}

View file

@ -1,6 +1,8 @@
pub mod analyzer;
pub mod ast;
pub mod compiler;
pub mod lexer;
pub mod ops;
pub mod parser;
use compiler::text;
@ -39,49 +41,3 @@ pub struct Jar(
pub trait Db: salsa::DbWithJar<Jar> {}
impl<DB> Db for DB where DB: ?Sized + salsa::DbWithJar<Jar> {}
#[macro_export]
macro_rules! visitor {
($(#[$meta:meta])* $vis:vis struct $name:ident($($field:ident: $ty:ty),*);) => {
$(#[$meta])*
$vis struct $name($($field: $ty),*);
paste::paste! {
trait [<$name Visitor>] {
$(
visitor!(@visit $field, $ty);
)*
}
}
};
(@visit $field:ident, Spanned<$t:ty>) => {
paste::paste! {
fn [<visit_ $t:snake _field>](&mut self, $t, Range<Location>);
}
};
(@visit $field:ident, Option<Spanned<$t:ty>>) => {
paste::paste! {
fn [<visit_ $t:snake _field>](&mut self, Option<$t>, Range<Location>);
}
};
(@visit $field:ident, Box<Spanned<$t:ty>>) => {
paste::paste! {
fn [<visit_ $t:snake _field>](&mut self, $t, Range<Location>);
}
};
(@visit $field:ident, Vec<Spanned<$t:ty>>) => {
paste::paste! {
fn [<visit_ $t:snake _field>](&mut self, $t, Range<Location>);
}
};
(@visit $field:ident, Block<Spanned<$t:ty>>) => {
paste::paste! {
fn [<visit_ $t:snake _field>](&mut self, $t, Range<Location>);
}
};
}

10
src/ops/mod.rs Normal file
View file

@ -0,0 +1,10 @@
/// This module contains the srclang ops.
pub mod traversal {
/// The result of a traversal operation.
pub enum Result {
/// Continue the traversal.
Continue,
/// Stop the traversal.
Break,
}
}

View file

@ -1,7 +1,8 @@
use std::fmt::Display;
use std::{fmt::Display, ops::Range};
pub const ANON_FN_NAME: &str = "anonymous";
use crate::visitor;
use super::span;
use super::span::*;
use src_derive::node;
use super::span::*;
@ -13,6 +14,7 @@ impl Display for Ident {
write!(f, "{}", self.0)
}
}
#[derive(PartialEq, Debug, Clone, Default)]
pub enum Visibility {
#[default]
@ -20,8 +22,6 @@ pub enum Visibility {
Public,
}
impl Display for Visibility {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@ -34,7 +34,6 @@ impl Display for Visibility {
#[derive(PartialEq, Debug, Clone)]
pub struct StringLit(pub String);
#[derive(PartialEq, Debug, Clone)]
pub struct Binding(pub Spanned<Ident>, pub Box<Spanned<Node>>);
@ -69,6 +68,8 @@ pub enum Keyword {
Self_,
}
trait KeywordVisitor {}
impl Display for Keyword {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let kw = match self {
@ -284,7 +285,7 @@ impl Display for FieldDef {
#[derive(PartialEq, Debug, Clone)]
pub struct StructDef(
pub KeywordAndVisibility,
pub Spanned<KeywordAndVisibility>,
pub Spanned<Ident>,
pub Block<Spanned<FieldDef>>,
);
@ -294,7 +295,7 @@ pub struct FnIdent(pub Ident);
#[derive(PartialEq, Debug, Clone)]
pub struct EffectDef(
pub KeywordAndVisibility,
pub Spanned<KeywordAndVisibility>,
pub Spanned<Ident>,
pub Vec<Spanned<Ident>>,
pub Block<Spanned<Prototype>>,
@ -302,7 +303,7 @@ pub struct EffectDef(
#[derive(PartialEq, Debug, Clone)]
pub struct UseDef(
pub KeywordAndVisibility,
pub Spanned<KeywordAndVisibility>,
pub Vec<Spanned<Ident>>,
pub Spanned<Ident>,
);
@ -324,7 +325,7 @@ impl Display for KeywordAndVisibility {
#[derive(PartialEq, Debug, Clone)]
pub struct ImplDef(
pub KeywordAndVisibility,
pub Spanned<KeywordAndVisibility>,
pub Spanned<Ident>,
pub Option<Spanned<Ident>>,
pub Block<Spanned<Node>>,
@ -336,12 +337,12 @@ pub struct BranchDef(
pub Vec<(Spanned<Node>, Block<Spanned<Node>>)>,
);
// #[visitor]
#[derive(PartialEq, Debug, Clone)]
pub struct FnDef(
pub KeywordAndVisibility,
pub Spanned<KeywordAndVisibility>,
pub Spanned<Prototype>,
pub Block<Spanned<Node>>,
pub Vec<(Spanned<Ident>, Block<Spanned<Node>>)>,
);
impl Display for FnDef {
@ -374,3 +375,26 @@ impl Arbitrary for Operator {
}
impl Eq for Node {}
#[cfg(test)]
mod test {
use crate::analyzer;
use super::*;
use proptest::prelude::*;
struct TestVisitor;
#[test]
fn test_binding_vistior() {
let input = "fn some()[] {let a = some_fnExpr(1, \"2\", 3)}";
let mut errors = vec![];
let wrapper = crate::lexer::TripleIterator::new(input);
let db = analyzer::db::Database::default();
let t = crate::parser::src::SourceParser::new().parse(&mut errors, &db, wrapper);
assert!(errors.is_empty());
assert!(t.is_ok());
let t = t.unwrap();
}
}

View file

@ -1,111 +1,118 @@
// use crate::{lexer::Coord, parser::errors::pretty_errors};
// use insta::assert_snapshot;
use crate::{analyzer, lexer::Location, parser::errors::pretty_errors};
use insta::assert_snapshot;
#[cfg(test)]
#[okstd::test]
fn test_empty_parser() {
use crate::analyzer;
// #[cfg(test)]
// #[okstd::test]
// fn test_empty_parser() {
// let input = " ";
// let mut errors = vec![];
// let wrapper = crate::lexer::TripleIterator::new(input);
// let t: Result<crate::parser::ast::Module, lalrpop_util::ParseError<Coord, crate::lexer::Token, &str>> = crate::parser::src::SourceParser::new().parse(&mut errors, wrapper);
// assert!(errors.is_empty());
// let fmted = format!("{:#?}", t.unwrap());
// assert_snapshot!(fmted, @r###"
// Module(
// [],
// )
// "###);
// }
let input = " ";
let mut errors = vec![];
let wrapper = crate::lexer::TripleIterator::new(input);
let db = analyzer::db::Database::default();
let t = crate::parser::src::SourceParser::new().parse(&mut errors, &db, wrapper);
assert!(errors.is_empty());
let fmted = format!("{:#?}", t.unwrap());
assert_snapshot!(fmted, @r###"
Module(
[],
)
"###);
}
// #[okstd::test]
// fn test_fn_call_parser_with_multiple_args_and_strings() {
// let input = "fn some()[] {let a = some_fnExpr(1, \"2\", 3)}";
// let mut errors = vec![];
// let wrapper = crate::lexer::TripleIterator::new(input);
// let t = crate::parser::src::SourceParser::new().parse(&mut errors, wrapper);
// if !errors.is_empty() {
// panic!("{}", pretty_errors(&input, errors));
// }
// assert_snapshot!(format!("{:#?}", t.unwrap()));
// }
#[okstd::test]
fn test_fn_call_parser_with_multiple_args_and_strings() {
let input = "fn some()[] {let a = some_fnExpr(1, \"2\", 3)}";
let mut errors = vec![];
let wrapper = crate::lexer::TripleIterator::new(input);
let db = analyzer::db::Database::default();
let t = crate::parser::src::SourceParser::new().parse(&mut errors, &db, wrapper);
if !errors.is_empty() {
panic!("{}", pretty_errors(&input, errors));
}
assert_snapshot!(format!("{:#?}", t.unwrap()));
}
// #[okstd::test]
// fn test_fn_def_parser() {
// let input = r#"fn call(a:b, b:c) [throws, awaits, execs] {
// call(1+1)
// let a = 1
// } when throws {
// raise(1)
// }"#;
// let mut errors = vec![];
// let wrapper = crate::lexer::TripleIterator::new(input);
// let t = crate::parser::src::SourceParser::new().parse(&mut errors, wrapper);
// assert!(errors.is_empty());
// assert_snapshot!(format!("{:#?}", t.unwrap()));
// }
#[okstd::test]
fn test_fn_def_parser() {
let input = r#"fn call(a:b, b:c) [throws, awaits, execs] {
call(1+1)
let a = 1
}"#;
let mut errors = vec![];
let wrapper = crate::lexer::TripleIterator::new(input);
let db = analyzer::db::Database::default();
let t = crate::parser::src::SourceParser::new().parse(&mut errors, &db, wrapper);
if !errors.is_empty() {
panic!("{}", pretty_errors(&input, errors));
}
assert_snapshot!(format!("{:#?}", t.unwrap()));
}
// #[okstd::test]
// fn test_effect() {
// let input = r#"effect VM: async + throws + execs {
// catch() []
// await<T>(f: Future<T>) [] -> T
// exec(arg0: string, args: stringvec) []
// }"#;
// let mut errors = vec![];
// let wrapper = crate::lexer::TripleIterator::new(input);
// let t = crate::parser::src::SourceParser::new().parse(&mut errors, wrapper);
// assert!(errors.is_empty());
// assert_snapshot!(format!("{:#?}", t.unwrap()));
// }
#[okstd::test]
fn test_effect() {
let input = r#"effect VM: async + throws + execs {
catch() []
await<T>(f: Future<T>) [] -> T
exec(arg0: string, args: stringvec) []
}"#;
let mut errors = vec![];
let wrapper = crate::lexer::TripleIterator::new(input);
let db = analyzer::db::Database::default();
let t = crate::parser::src::SourceParser::new().parse(&mut errors, &db, wrapper);
assert!(errors.is_empty());
assert_snapshot!(format!("{:#?}", t.unwrap()));
}
// #[okstd::test]
// fn test_struct_parser() {
// let input = r#"struct VM {
// a: string
// b: string
// }"#;
// let mut errors = vec![];
// let wrapper = crate::lexer::TripleIterator::new(input);
// let t = crate::parser::src::SourceParser::new().parse(&mut errors, wrapper);
// assert!(errors.is_empty());
// assert_snapshot!(format!("{:#?}", t.unwrap()));
// }
#[okstd::test]
fn test_struct_parser() {
let input = r#"struct VM {
a: string
b: string
}"#;
let mut errors = vec![];
let wrapper = crate::lexer::TripleIterator::new(input);
let db = analyzer::db::Database::default();
let t = crate::parser::src::SourceParser::new().parse(&mut errors, &db, wrapper);
assert!(errors.is_empty());
assert_snapshot!(format!("{:#?}", t.unwrap()));
}
// #[okstd::test]
// fn test_enum_parser() {
// let input = r#"use { exec } from host
#[okstd::test]
fn test_enum_parser() {
let input = r#"use { exec } from host
// effect Make: async + throws + execs + reads + writes {
// catch() [throws]
// await<T>(f: Future<T>) [async, throws] -> T
// exec(arg0: string, args: stringvec) [Make] -> i32
// read(name: string) [reads] -> string
// write(name: string, value: string) [writes]
// }
// struct Local {
// host: host
// }
// impl Make for Local {
// fn catch(self) [throws] {
// }
// fn await<T>(f: Future<T>) [async, trhows] -> T {
// yield()
// }
// fn exec(self, arg0: string, args: vec<string>) [Vm] -> i32 {
// self.host.read("jobserver").await
// if self.host.exec(arg0, args).await {
// raise(1)
// }
// }
// }"#;
// let mut errors: Vec<lalrpop_util::ErrorRecovery<Coord, crate::lexer::Token, &str>> = vec![];
// let wrapper = crate::lexer::TripleIterator::new(input);
// let t = crate::parser::src::SourceParser::new().parse(&mut errors, wrapper);
// if !errors.is_empty() {
// panic!("{}", pretty_errors(&input, errors));
// }
// assert_snapshot!(format!("{:#?}", t.unwrap()));
// }
effect Make: async + throws + execs + reads + writes {
catch() [throws]
await<T>(f: Future<T>) [async, throws] -> T
exec(arg0: string, args: stringvec) [Make] -> i32
read(name: string) [reads] -> string
write(name: string, value: string) [writes]
}
struct Local {
host: host
}
impl Make for Local {
fn catch(self) [throws] {
}
fn await<T>(f: Future<T>) [async, trhows] -> T {
yield()
}
fn exec(self, arg0: string, args: vec<string>) [Vm] -> i32 {
self.host.read("jobserver").await
if self.host.exec(arg0, args).await {
raise(1)
}
}
}"#;
let mut errors = vec![];
let wrapper = crate::lexer::TripleIterator::new(input);
let db = analyzer::db::Database::default();
let t = crate::parser::src::SourceParser::new().parse(&mut errors, &db, wrapper);
if !errors.is_empty() {
panic!("{}", pretty_errors(&input, errors));
}
assert_snapshot!(format!("{:#?}", t.unwrap()));
}

View file

@ -5,43 +5,55 @@ expression: "format!(\"{:#?}\", t.unwrap())"
Module(
[
Spanned(
Coord {
Location {
offset: 0,
line: 0,
col: 0,
},
EffectDef(
EffectDef(
KeywordAndVisibility(
Spanned(
Coord {
offset: 0,
line: 0,
col: 0,
},
Effect,
Coord {
offset: 6,
line: 0,
col: 6,
},
),
Spanned(
Coord {
offset: 0,
line: 0,
col: 0,
},
Private,
Coord {
offset: 0,
line: 0,
col: 0,
},
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
KeywordAndVisibility(
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
Effect,
Location {
offset: 6,
line: 0,
col: 6,
},
),
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
Private,
Location {
offset: 0,
line: 0,
col: 0,
},
),
),
Location {
offset: 6,
line: 0,
col: 6,
},
),
Spanned(
Coord {
Location {
offset: 7,
line: 0,
col: 7,
@ -50,7 +62,7 @@ Module(
"VM",
None,
),
Coord {
Location {
offset: 9,
line: 0,
col: 9,
@ -58,7 +70,7 @@ Module(
),
[
Spanned(
Coord {
Location {
offset: 11,
line: 0,
col: 11,
@ -67,14 +79,14 @@ Module(
"async",
None,
),
Coord {
Location {
offset: 16,
line: 0,
col: 16,
},
),
Spanned(
Coord {
Location {
offset: 19,
line: 0,
col: 19,
@ -83,14 +95,14 @@ Module(
"throws",
None,
),
Coord {
Location {
offset: 25,
line: 0,
col: 25,
},
),
Spanned(
Coord {
Location {
offset: 28,
line: 0,
col: 28,
@ -99,7 +111,7 @@ Module(
"execs",
None,
),
Coord {
Location {
offset: 33,
line: 0,
col: 33,
@ -109,388 +121,388 @@ Module(
Block(
[
Spanned(
Coord {
offset: 44,
Location {
offset: 40,
line: 1,
col: 8,
col: 4,
},
Prototype {
name: Spanned(
Coord {
offset: 44,
Location {
offset: 40,
line: 1,
col: 8,
col: 4,
},
Ident(
"catch",
None,
),
Coord {
offset: 49,
Location {
offset: 45,
line: 1,
col: 13,
col: 9,
},
),
args: [],
ret: None,
effects: [],
},
Coord {
offset: 54,
Location {
offset: 50,
line: 1,
col: 18,
col: 14,
},
),
Spanned(
Coord {
offset: 63,
Location {
offset: 55,
line: 2,
col: 8,
col: 4,
},
Prototype {
name: Spanned(
Coord {
offset: 63,
Location {
offset: 55,
line: 2,
col: 8,
col: 4,
},
Ident(
"await",
Some(
[
Spanned(
Coord {
offset: 69,
Location {
offset: 61,
line: 2,
col: 14,
col: 10,
},
Ident(
"T",
None,
),
Coord {
offset: 70,
Location {
offset: 62,
line: 2,
col: 15,
col: 11,
},
),
],
),
),
Coord {
offset: 71,
Location {
offset: 63,
line: 2,
col: 16,
col: 12,
},
),
args: [
Spanned(
Coord {
offset: 72,
Location {
offset: 64,
line: 2,
col: 17,
col: 13,
},
Field(
Spanned(
Coord {
offset: 72,
Location {
offset: 64,
line: 2,
col: 17,
col: 13,
},
FieldDef(
Spanned(
Coord {
offset: 72,
Location {
offset: 64,
line: 2,
col: 17,
col: 13,
},
Private,
Coord {
offset: 72,
Location {
offset: 64,
line: 2,
col: 17,
col: 13,
},
),
Spanned(
Coord {
offset: 72,
Location {
offset: 64,
line: 2,
col: 17,
col: 13,
},
Ident(
"f",
None,
),
Coord {
offset: 73,
Location {
offset: 65,
line: 2,
col: 18,
col: 14,
},
),
Spanned(
Coord {
offset: 75,
Location {
offset: 67,
line: 2,
col: 20,
col: 16,
},
Ident(
"Future",
Some(
[
Spanned(
Coord {
offset: 82,
Location {
offset: 74,
line: 2,
col: 27,
col: 23,
},
Ident(
"T",
None,
),
Coord {
offset: 83,
Location {
offset: 75,
line: 2,
col: 28,
col: 24,
},
),
],
),
),
Coord {
offset: 84,
Location {
offset: 76,
line: 2,
col: 29,
col: 25,
},
),
),
Coord {
offset: 84,
Location {
offset: 76,
line: 2,
col: 29,
col: 25,
},
),
),
Coord {
offset: 84,
Location {
offset: 76,
line: 2,
col: 29,
col: 25,
},
),
],
ret: Some(
Spanned(
Coord {
offset: 92,
Location {
offset: 84,
line: 2,
col: 37,
col: 33,
},
Ident(
"T",
None,
),
Coord {
offset: 93,
Location {
offset: 85,
line: 2,
col: 38,
col: 34,
},
),
),
effects: [],
},
Coord {
offset: 93,
Location {
offset: 85,
line: 2,
col: 38,
col: 34,
},
),
Spanned(
Coord {
offset: 102,
Location {
offset: 90,
line: 3,
col: 8,
col: 4,
},
Prototype {
name: Spanned(
Coord {
offset: 102,
Location {
offset: 90,
line: 3,
col: 8,
col: 4,
},
Ident(
"exec",
None,
),
Coord {
offset: 106,
Location {
offset: 94,
line: 3,
col: 12,
col: 8,
},
),
args: [
Spanned(
Coord {
offset: 107,
Location {
offset: 95,
line: 3,
col: 13,
col: 9,
},
Field(
Spanned(
Coord {
offset: 107,
Location {
offset: 95,
line: 3,
col: 13,
col: 9,
},
FieldDef(
Spanned(
Coord {
offset: 107,
Location {
offset: 95,
line: 3,
col: 13,
col: 9,
},
Private,
Coord {
offset: 107,
Location {
offset: 95,
line: 3,
col: 13,
col: 9,
},
),
Spanned(
Coord {
offset: 107,
Location {
offset: 95,
line: 3,
col: 13,
col: 9,
},
Ident(
"arg0",
None,
),
Coord {
offset: 111,
Location {
offset: 99,
line: 3,
col: 17,
col: 13,
},
),
Spanned(
Coord {
offset: 113,
Location {
offset: 101,
line: 3,
col: 19,
col: 15,
},
Ident(
"string",
None,
),
Coord {
offset: 119,
Location {
offset: 107,
line: 3,
col: 25,
col: 21,
},
),
),
Coord {
offset: 119,
Location {
offset: 107,
line: 3,
col: 25,
col: 21,
},
),
),
Coord {
offset: 119,
Location {
offset: 107,
line: 3,
col: 25,
col: 21,
},
),
Spanned(
Coord {
offset: 121,
Location {
offset: 109,
line: 3,
col: 27,
col: 23,
},
Field(
Spanned(
Coord {
offset: 121,
Location {
offset: 109,
line: 3,
col: 27,
col: 23,
},
FieldDef(
Spanned(
Coord {
offset: 121,
Location {
offset: 109,
line: 3,
col: 27,
col: 23,
},
Private,
Coord {
offset: 121,
Location {
offset: 109,
line: 3,
col: 27,
col: 23,
},
),
Spanned(
Coord {
offset: 121,
Location {
offset: 109,
line: 3,
col: 27,
col: 23,
},
Ident(
"args",
None,
),
Coord {
offset: 125,
Location {
offset: 113,
line: 3,
col: 31,
col: 27,
},
),
Spanned(
Coord {
offset: 127,
Location {
offset: 115,
line: 3,
col: 33,
col: 29,
},
Ident(
"stringvec",
None,
),
Coord {
offset: 136,
Location {
offset: 124,
line: 3,
col: 42,
col: 38,
},
),
),
Coord {
offset: 136,
Location {
offset: 124,
line: 3,
col: 42,
col: 38,
},
),
),
Coord {
offset: 136,
Location {
offset: 124,
line: 3,
col: 42,
col: 38,
},
),
],
ret: None,
effects: [],
},
Coord {
offset: 140,
Location {
offset: 128,
line: 3,
col: 46,
col: 42,
},
),
],
),
),
),
Coord {
offset: 146,
Location {
offset: 130,
line: 4,
col: 5,
col: 1,
},
),
],

View file

@ -5,50 +5,62 @@ expression: "format!(\"{:#?}\", t.unwrap())"
Module(
[
Spanned(
Coord {
Location {
offset: 0,
line: 0,
col: 0,
},
FnDef(
FnDef(
KeywordAndVisibility(
Spanned(
Coord {
offset: 0,
line: 0,
col: 0,
},
Fn,
Coord {
offset: 2,
line: 0,
col: 2,
},
),
Spanned(
Coord {
offset: 0,
line: 0,
col: 0,
},
Private,
Coord {
offset: 0,
line: 0,
col: 0,
},
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
KeywordAndVisibility(
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
Fn,
Location {
offset: 2,
line: 0,
col: 2,
},
),
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
Private,
Location {
offset: 0,
line: 0,
col: 0,
},
),
),
Location {
offset: 2,
line: 0,
col: 2,
},
),
Spanned(
Coord {
Location {
offset: 3,
line: 0,
col: 3,
},
Prototype {
name: Spanned(
Coord {
Location {
offset: 3,
line: 0,
col: 3,
@ -57,7 +69,7 @@ Module(
"some",
None,
),
Coord {
Location {
offset: 7,
line: 0,
col: 7,
@ -67,7 +79,7 @@ Module(
ret: None,
effects: [],
},
Coord {
Location {
offset: 11,
line: 0,
col: 11,
@ -76,7 +88,7 @@ Module(
Block(
[
Spanned(
Coord {
Location {
offset: 13,
line: 0,
col: 13,
@ -84,7 +96,7 @@ Module(
Binding(
Binding(
Spanned(
Coord {
Location {
offset: 17,
line: 0,
col: 17,
@ -93,14 +105,14 @@ Module(
"a",
None,
),
Coord {
Location {
offset: 18,
line: 0,
col: 18,
},
),
Spanned(
Coord {
Location {
offset: 21,
line: 0,
col: 21,
@ -108,7 +120,7 @@ Module(
FnCall(
FnCall(
Spanned(
Coord {
Location {
offset: 21,
line: 0,
col: 21,
@ -117,7 +129,7 @@ Module(
"some_fnExpr",
None,
),
Coord {
Location {
offset: 32,
line: 0,
col: 32,
@ -125,7 +137,7 @@ Module(
),
[
Spanned(
Coord {
Location {
offset: 33,
line: 0,
col: 33,
@ -133,14 +145,14 @@ Module(
Integer(
1,
),
Coord {
Location {
offset: 34,
line: 0,
col: 34,
},
),
Spanned(
Coord {
Location {
offset: 36,
line: 0,
col: 36,
@ -148,14 +160,14 @@ Module(
String(
"2",
),
Coord {
Location {
offset: 39,
line: 0,
col: 39,
},
),
Spanned(
Coord {
Location {
offset: 41,
line: 0,
col: 41,
@ -163,7 +175,7 @@ Module(
Integer(
3,
),
Coord {
Location {
offset: 42,
line: 0,
col: 42,
@ -172,7 +184,7 @@ Module(
],
),
),
Coord {
Location {
offset: 43,
line: 0,
col: 43,
@ -180,7 +192,7 @@ Module(
),
),
),
Coord {
Location {
offset: 43,
line: 0,
col: 43,
@ -188,10 +200,9 @@ Module(
),
],
),
[],
),
),
Coord {
Location {
offset: 44,
line: 0,
col: 44,

View file

@ -5,50 +5,62 @@ expression: "format!(\"{:#?}\", t.unwrap())"
Module(
[
Spanned(
Coord {
Location {
offset: 0,
line: 0,
col: 0,
},
FnDef(
FnDef(
KeywordAndVisibility(
Spanned(
Coord {
offset: 0,
line: 0,
col: 0,
},
Fn,
Coord {
offset: 2,
line: 0,
col: 2,
},
),
Spanned(
Coord {
offset: 0,
line: 0,
col: 0,
},
Private,
Coord {
offset: 0,
line: 0,
col: 0,
},
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
KeywordAndVisibility(
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
Fn,
Location {
offset: 2,
line: 0,
col: 2,
},
),
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
Private,
Location {
offset: 0,
line: 0,
col: 0,
},
),
),
Location {
offset: 2,
line: 0,
col: 2,
},
),
Spanned(
Coord {
Location {
offset: 3,
line: 0,
col: 3,
},
Prototype {
name: Spanned(
Coord {
Location {
offset: 3,
line: 0,
col: 3,
@ -57,7 +69,7 @@ Module(
"call",
None,
),
Coord {
Location {
offset: 7,
line: 0,
col: 7,
@ -65,34 +77,34 @@ Module(
),
args: [
Spanned(
Coord {
Location {
offset: 8,
line: 0,
col: 8,
},
Field(
Spanned(
Coord {
Location {
offset: 8,
line: 0,
col: 8,
},
FieldDef(
Spanned(
Coord {
Location {
offset: 8,
line: 0,
col: 8,
},
Private,
Coord {
Location {
offset: 8,
line: 0,
col: 8,
},
),
Spanned(
Coord {
Location {
offset: 8,
line: 0,
col: 8,
@ -101,14 +113,14 @@ Module(
"a",
None,
),
Coord {
Location {
offset: 9,
line: 0,
col: 9,
},
),
Spanned(
Coord {
Location {
offset: 10,
line: 0,
col: 10,
@ -117,55 +129,55 @@ Module(
"b",
None,
),
Coord {
Location {
offset: 11,
line: 0,
col: 11,
},
),
),
Coord {
Location {
offset: 11,
line: 0,
col: 11,
},
),
),
Coord {
Location {
offset: 11,
line: 0,
col: 11,
},
),
Spanned(
Coord {
Location {
offset: 13,
line: 0,
col: 13,
},
Field(
Spanned(
Coord {
Location {
offset: 13,
line: 0,
col: 13,
},
FieldDef(
Spanned(
Coord {
Location {
offset: 13,
line: 0,
col: 13,
},
Private,
Coord {
Location {
offset: 13,
line: 0,
col: 13,
},
),
Spanned(
Coord {
Location {
offset: 13,
line: 0,
col: 13,
@ -174,14 +186,14 @@ Module(
"b",
None,
),
Coord {
Location {
offset: 14,
line: 0,
col: 14,
},
),
Spanned(
Coord {
Location {
offset: 15,
line: 0,
col: 15,
@ -190,21 +202,21 @@ Module(
"c",
None,
),
Coord {
Location {
offset: 16,
line: 0,
col: 16,
},
),
),
Coord {
Location {
offset: 16,
line: 0,
col: 16,
},
),
),
Coord {
Location {
offset: 16,
line: 0,
col: 16,
@ -214,7 +226,7 @@ Module(
ret: None,
effects: [
Spanned(
Coord {
Location {
offset: 19,
line: 0,
col: 19,
@ -223,14 +235,14 @@ Module(
"throws",
None,
),
Coord {
Location {
offset: 25,
line: 0,
col: 25,
},
),
Spanned(
Coord {
Location {
offset: 27,
line: 0,
col: 27,
@ -239,14 +251,14 @@ Module(
"awaits",
None,
),
Coord {
Location {
offset: 33,
line: 0,
col: 33,
},
),
Spanned(
Coord {
Location {
offset: 35,
line: 0,
col: 35,
@ -255,7 +267,7 @@ Module(
"execs",
None,
),
Coord {
Location {
offset: 40,
line: 0,
col: 40,
@ -263,7 +275,7 @@ Module(
),
],
},
Coord {
Location {
offset: 41,
line: 0,
col: 41,
@ -272,214 +284,141 @@ Module(
Block(
[
Spanned(
Coord {
offset: 52,
Location {
offset: 48,
line: 1,
col: 8,
col: 4,
},
FnCall(
FnCall(
Spanned(
Coord {
offset: 52,
Location {
offset: 48,
line: 1,
col: 8,
col: 4,
},
Ident(
"call",
None,
),
Coord {
offset: 56,
Location {
offset: 52,
line: 1,
col: 12,
col: 8,
},
),
[
Spanned(
Coord {
offset: 58,
Location {
offset: 54,
line: 1,
col: 14,
col: 10,
},
BinaryExpression(
BinaryOperation {
lhs: Spanned(
Coord {
offset: 57,
Location {
offset: 53,
line: 1,
col: 13,
col: 9,
},
Integer(
1,
),
Coord {
offset: 58,
Location {
offset: 54,
line: 1,
col: 14,
col: 10,
},
),
op: Add,
rhs: Spanned(
Coord {
offset: 59,
Location {
offset: 55,
line: 1,
col: 15,
col: 11,
},
Integer(
1,
),
Coord {
offset: 60,
Location {
offset: 56,
line: 1,
col: 16,
col: 12,
},
),
},
),
Coord {
offset: 59,
Location {
offset: 55,
line: 1,
col: 15,
col: 11,
},
),
],
),
),
Coord {
offset: 61,
Location {
offset: 57,
line: 1,
col: 17,
col: 13,
},
),
Spanned(
Coord {
offset: 70,
Location {
offset: 62,
line: 2,
col: 8,
col: 4,
},
Binding(
Binding(
Spanned(
Coord {
offset: 74,
Location {
offset: 66,
line: 2,
col: 12,
col: 8,
},
Ident(
"a",
None,
),
Coord {
offset: 75,
Location {
offset: 67,
line: 2,
col: 13,
col: 9,
},
),
Spanned(
Coord {
offset: 78,
Location {
offset: 70,
line: 2,
col: 16,
col: 12,
},
Integer(
1,
),
Coord {
offset: 79,
Location {
offset: 71,
line: 2,
col: 17,
col: 13,
},
),
),
),
Coord {
offset: 79,
Location {
offset: 71,
line: 2,
col: 17,
col: 13,
},
),
],
),
[
(
Spanned(
Coord {
offset: 91,
line: 3,
col: 11,
},
Ident(
"throws",
None,
),
Coord {
offset: 97,
line: 3,
col: 17,
},
),
Block(
[
Spanned(
Coord {
offset: 108,
line: 4,
col: 8,
},
FnCall(
FnCall(
Spanned(
Coord {
offset: 108,
line: 4,
col: 8,
},
Ident(
"raise",
None,
),
Coord {
offset: 113,
line: 4,
col: 13,
},
),
[
Spanned(
Coord {
offset: 114,
line: 4,
col: 14,
},
Integer(
1,
),
Coord {
offset: 115,
line: 4,
col: 15,
},
),
],
),
),
Coord {
offset: 116,
line: 4,
col: 16,
},
),
],
),
),
],
),
),
Coord {
offset: 122,
line: 5,
col: 5,
Location {
offset: 73,
line: 3,
col: 1,
},
),
],

View file

@ -5,43 +5,55 @@ expression: "format!(\"{:#?}\", t.unwrap())"
Module(
[
Spanned(
Coord {
Location {
offset: 0,
line: 0,
col: 0,
},
StructDef(
StructDef(
KeywordAndVisibility(
Spanned(
Coord {
offset: 0,
line: 0,
col: 0,
},
Struct,
Coord {
offset: 6,
line: 0,
col: 6,
},
),
Spanned(
Coord {
offset: 0,
line: 0,
col: 0,
},
Private,
Coord {
offset: 0,
line: 0,
col: 0,
},
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
KeywordAndVisibility(
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
Struct,
Location {
offset: 6,
line: 0,
col: 6,
},
),
Spanned(
Location {
offset: 0,
line: 0,
col: 0,
},
Private,
Location {
offset: 0,
line: 0,
col: 0,
},
),
),
Location {
offset: 6,
line: 0,
col: 6,
},
),
Spanned(
Coord {
Location {
offset: 7,
line: 0,
col: 7,
@ -50,7 +62,7 @@ Module(
"VM",
None,
),
Coord {
Location {
offset: 9,
line: 0,
col: 9,
@ -59,131 +71,131 @@ Module(
Block(
[
Spanned(
Coord {
offset: 20,
Location {
offset: 16,
line: 1,
col: 8,
col: 4,
},
FieldDef(
Spanned(
Coord {
offset: 20,
Location {
offset: 16,
line: 1,
col: 8,
col: 4,
},
Private,
Coord {
offset: 20,
Location {
offset: 16,
line: 1,
col: 8,
col: 4,
},
),
Spanned(
Coord {
offset: 20,
Location {
offset: 16,
line: 1,
col: 8,
col: 4,
},
Ident(
"a",
None,
),
Coord {
offset: 21,
Location {
offset: 17,
line: 1,
col: 9,
col: 5,
},
),
Spanned(
Coord {
offset: 23,
Location {
offset: 19,
line: 1,
col: 11,
col: 7,
},
Ident(
"string",
None,
),
Coord {
offset: 29,
Location {
offset: 25,
line: 1,
col: 17,
col: 13,
},
),
),
Coord {
offset: 29,
Location {
offset: 25,
line: 1,
col: 17,
col: 13,
},
),
Spanned(
Coord {
offset: 38,
Location {
offset: 30,
line: 2,
col: 8,
col: 4,
},
FieldDef(
Spanned(
Coord {
offset: 38,
Location {
offset: 30,
line: 2,
col: 8,
col: 4,
},
Private,
Coord {
offset: 38,
Location {
offset: 30,
line: 2,
col: 8,
col: 4,
},
),
Spanned(
Coord {
offset: 38,
Location {
offset: 30,
line: 2,
col: 8,
col: 4,
},
Ident(
"b",
None,
),
Coord {
offset: 39,
Location {
offset: 31,
line: 2,
col: 9,
col: 5,
},
),
Spanned(
Coord {
offset: 41,
Location {
offset: 33,
line: 2,
col: 11,
col: 7,
},
Ident(
"string",
None,
),
Coord {
offset: 47,
Location {
offset: 39,
line: 2,
col: 17,
col: 13,
},
),
),
Coord {
offset: 47,
Location {
offset: 39,
line: 2,
col: 17,
col: 13,
},
),
],
),
),
),
Coord {
offset: 53,
Location {
offset: 41,
line: 3,
col: 5,
col: 1,
},
),
],

View file

@ -1,4 +1,4 @@
use crate::{lexer::Location, Db};
pub use crate::{lexer::Location, Db};
use hashbrown::HashMap;
use okstd::prelude::*;
use std::{fmt::Display, ops::Range};
@ -17,6 +17,17 @@ impl<T> Spanned<T> {
}
}
trait GetSelf<T> {
fn into(self) -> T;
}
impl<T> GetSelf<T> for Spanned<T> {
fn into(self) -> T {
self.1
}
}
impl<T: Display> Display for Spanned<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.1)

View file

@ -145,8 +145,8 @@ Let: Spanned<Keyword> = <lo:@L> "let" <hi:@R> => span!(lo, Keyword::Let, hi);
True: Node = "true" => Node::Bool(true);
False: Node = "false" => Node::Bool(false);
KeywordAndVisibility<T>: KeywordAndVisibility = {
<v:Visibility> <k:T> => KeywordAndVisibility(k, v),
KeywordAndVisibility<T>: Spanned<KeywordAndVisibility> = {
<lo:@L> <v:Visibility> <k:T> <hi:@R> => span!(lo, KeywordAndVisibility(k, v), hi),
};
Ident: Spanned<Ident> = {
@ -321,7 +321,7 @@ WhenBlock: (Spanned<Ident>,Block<Spanned<Node>>) = {
};
FnDef: Spanned<Node> = {
<l:@L> <kwv:KeywordAndVisibility<Fn>> <proto:Prototype> <block:Block<Statement>> <handlers:(WhenBlock)*> <r:@R> => span!(l, Node::FnDef(FnDef(kwv,proto, block, handlers)), r),
<l:@L> <kwv:KeywordAndVisibility<Fn>> <proto:Prototype> <block:Block<Statement>> <r:@R> => span!(l, Node::FnDef(FnDef(kwv,proto, block)), r),
};
EffectDef: Spanned<Node> = {

File diff suppressed because it is too large Load diff