Compare commits

...

8 Commits

Author SHA1 Message Date
Jesse Brault
59165f6235 Build fn child unwrap; some tests. 2025-09-04 19:27:26 -05:00
Jesse Brault
4d70765d17 Wrap in Boxes. 2025-09-04 11:10:59 -05:00
Jesse Brault
0a97cc01b9 Add return value to build fn. 2025-09-04 11:08:23 -05:00
Jesse Brault
0adb4bbe0e Add or else (default) to yaml spec. 2025-09-04 10:21:30 -05:00
Jesse Brault
9f3f3e0f0d Implement optionality for types. 2025-09-03 17:12:19 -05:00
Jesse Brault
3b07cef209 Basic function types. 2025-09-03 17:05:15 -05:00
Jesse Brault
a53388155a Add optional to ast schema and ast-gen. 2025-09-03 16:45:09 -05:00
Jesse Brault
4dcb5ee783 Pest and ast syntax changes. 2025-09-03 16:39:31 -05:00
10 changed files with 432 additions and 104 deletions

View File

@ -1,5 +1,6 @@
use crate::spec::{ use crate::spec::{
BuildBooleanOn, ChildSpec, SingleChildToBuild, StructBuildSpec, VecChildToBuild, BuildBooleanOn, ChildSpec, SingleBooleanChildToBuild, SingleChildToBuild,
SingleTypeChildToBuild, StructBuildSpec, VecChild, VecChildToBuild,
}; };
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
@ -9,33 +10,45 @@ pub fn make_build_fn_name(s: &str) -> String {
format!("build_{}", s.to_case(Case::Snake)) format!("build_{}", s.to_case(Case::Snake))
} }
fn make_child_holder(child_spec: &ChildSpec) -> Option<TokenStream> { fn make_vec_child_holder(vec_child: &VecChild) -> TokenStream {
match child_spec {
ChildSpec::SkipChild(_) => None,
ChildSpec::VecChild(vec_child) => {
let (child_ident, child_type_ident) = match vec_child.build() { let (child_ident, child_type_ident) = match vec_child.build() {
VecChildToBuild::Type(vec_type_child) => ( VecChildToBuild::Type(vec_type_child) => (
format_ident!("{}", vec_type_child.var_name()), format_ident!("{}", vec_type_child.var_name()),
format_ident!("{}", vec_type_child.build()), format_ident!("{}", vec_type_child.build()),
), ),
}; };
Some(quote! { quote! {
let mut #child_ident: Vec<#child_type_ident> = vec![] let mut #child_ident: Vec<Box<#child_type_ident>> = vec![]
})
} }
ChildSpec::SingleChild(single_child) => match single_child.build() { }
SingleChildToBuild::Type(single_type_child) => {
fn make_single_type_child_holder(single_type_child: &SingleTypeChildToBuild) -> TokenStream {
let child_ident = format_ident!("{}", single_type_child.var_name()); let child_ident = format_ident!("{}", single_type_child.var_name());
let child_type_ident = format_ident!("{}", single_type_child.build()); let child_type_ident = format_ident!("{}", single_type_child.build());
Some(quote! { quote! {
let mut #child_ident: Option<#child_type_ident> = None; let mut #child_ident: Option<Box<#child_type_ident>> = None
}) }
}
fn make_single_boolean_child_holder(
single_boolean_child: &SingleBooleanChildToBuild,
) -> TokenStream {
let child_ident = format_ident!("{}", single_boolean_child.var_name());
quote! {
let mut #child_ident: bool = false
}
}
fn make_child_holder(child_spec: &ChildSpec) -> Option<TokenStream> {
match child_spec {
ChildSpec::SkipChild(_) => None,
ChildSpec::VecChild(vec_child) => Some(make_vec_child_holder(vec_child)),
ChildSpec::SingleChild(single_child) => match single_child.build() {
SingleChildToBuild::Type(single_type_child) => {
Some(make_single_type_child_holder(single_type_child))
} }
SingleChildToBuild::Boolean(boolean_child) => { SingleChildToBuild::Boolean(boolean_child) => {
let child_ident = format_ident!("{}", boolean_child.var_name()); Some(make_single_boolean_child_holder(boolean_child))
Some(quote! {
let #child_ident: bool = false
})
} }
}, },
} }
@ -52,7 +65,7 @@ fn make_match_action(child_spec: &ChildSpec) -> TokenStream {
), ),
}; };
quote! { quote! {
#child_name_ident.push(#build_fn_ident(inner_pair)) #child_name_ident.push(Box::new(#build_fn_ident(inner_pair)))
} }
} }
ChildSpec::SingleChild(single_child) => match single_child.build() { ChildSpec::SingleChild(single_child) => match single_child.build() {
@ -60,7 +73,7 @@ fn make_match_action(child_spec: &ChildSpec) -> TokenStream {
let child_name_ident = format_ident!("{}", single_type_child.var_name()); let child_name_ident = format_ident!("{}", single_type_child.var_name());
let build_fn_ident = format_ident!("{}", single_type_child.with()); let build_fn_ident = format_ident!("{}", single_type_child.with());
quote! { quote! {
#child_name_ident = Some(#build_fn_ident(inner_pair)) #child_name_ident = Some(Box::new(#build_fn_ident(inner_pair)))
} }
} }
SingleChildToBuild::Boolean(single_boolean_child) => { SingleChildToBuild::Boolean(single_boolean_child) => {
@ -90,6 +103,57 @@ fn make_rule_matcher(child_spec: &ChildSpec) -> TokenStream {
} }
} }
fn make_child_arg(child_spec: &ChildSpec) -> Option<TokenStream> {
match child_spec {
ChildSpec::SkipChild(_) => None,
ChildSpec::VecChild(vec_child) => {
let child_ident = match vec_child.build() {
VecChildToBuild::Type(vec_type_child) => {
format_ident!("{}", vec_type_child.var_name())
}
};
Some(quote! { #child_ident })
}
ChildSpec::SingleChild(single_child) => match single_child.build() {
SingleChildToBuild::Type(single_type_child) => {
let child_ident = format_ident!("{}", single_type_child.var_name());
if single_type_child.optional() {
Some(quote! { #child_ident })
} else if let Some(or_else) = single_type_child.or_else() {
let child_type_ident = format_ident!("{}", single_type_child.build());
let or_else_ident = format_ident!("{}", or_else);
Some(quote! {
#child_ident.unwrap_or_else(|| Box::new(#child_type_ident::#or_else_ident()))
})
} else {
Some(quote! { #child_ident.unwrap() })
}
}
SingleChildToBuild::Boolean(single_boolean_child) => {
let child_ident = format_ident!("{}", single_boolean_child.var_name());
Some(quote! { #child_ident })
}
},
}
}
fn make_return_value_stream(build_spec: &StructBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", build_spec.build());
let child_args = build_spec
.children()
.iter()
.map(|child| make_child_arg(child))
.filter(|child_arg| child_arg.is_some())
.map(|child_arg| child_arg.unwrap())
.collect::<Vec<_>>();
quote! {
#type_ident::new(
#(#child_args,)*
)
}
}
pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream { pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream {
let build_fn_ident = format_ident!("{}", build_spec.with()); let build_fn_ident = format_ident!("{}", build_spec.with());
let pair_ident = format_ident!("{}_pair", build_spec.build().to_case(Case::Snake)); let pair_ident = format_ident!("{}_pair", build_spec.build().to_case(Case::Snake));
@ -117,11 +181,66 @@ pub fn make_struct_build_fn(build_spec: &StructBuildSpec) -> TokenStream {
} }
}; };
let new_stream = make_return_value_stream(build_spec);
quote! { quote! {
fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident { fn #build_fn_ident(#pair_ident: Pair<Rule>) -> #return_type_ident {
#(#child_holders;)* #(#child_holders;)*
#iter_stream #iter_stream
#new_stream
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
use crate::spec::VecTypeChildToBuild;
#[test]
fn vec_child_holder() {
let vec_child = VecChild::new(
"test_child",
"Test",
VecChildToBuild::Type(VecTypeChildToBuild::new(
"TestType",
"test_child",
"build_test_child",
)),
);
assert_eq!(
make_vec_child_holder(&vec_child).to_string(),
quote! {
let mut test_child: Vec<Box<TestType>> = vec![]
}
.to_string()
);
}
#[test]
fn single_type_child_holder() {
let single_type_child = SingleTypeChildToBuild::from_build_or_rule("TestType", None, false);
assert_eq!(
make_single_type_child_holder(&single_type_child).to_string(),
quote! {
let mut test_type: Option<Box<TestType>> = None
}
.to_string()
);
}
#[test]
fn single_boolean_child_holder() {
let single_boolean_child =
SingleBooleanChildToBuild::new("test_child", BuildBooleanOn::RulePresent);
assert_eq!(
make_single_boolean_child_holder(&single_boolean_child).to_string(),
quote! {
let mut test_child: bool = false
}
.to_string()
);
}
}

View File

@ -46,9 +46,10 @@ fn get_vec_child(name: &str, rule: &str, build: &Yaml) -> ChildSpec {
)) ))
} }
fn get_single_child_to_build(name: &str, rule: &str, build: &Yaml) -> SingleChildToBuild { fn get_single_child_to_build(name: &str, rule: &str, optional: bool, build: &Yaml) -> SingleChildToBuild {
if build.is_hash() { if build.is_hash() {
let r#type = build["type"].as_str().unwrap(); match build["type"].as_str() {
Some(r#type) => {
let var_name = build["var"] let var_name = build["var"]
.as_str() .as_str()
.map(|s| s.to_string()) .map(|s| s.to_string())
@ -62,19 +63,41 @@ fn get_single_child_to_build(name: &str, rule: &str, build: &Yaml) -> SingleChil
} else { } else {
todo!("currently on boolean types with on: rule_present are supported") todo!("currently on boolean types with on: rule_present are supported")
} }
},
None => {
let or_else = build["or_else"]
.as_str()
.map(|s| s.to_string())
.or_else(|| {
let or_else_default = build["or_else_default"]
.as_bool()
.unwrap_or_else(|| false);
if or_else_default {
Some(String::from("default"))
} else {
None
}
});
SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(
rule,
or_else,
optional,
))
}
}
} else { } else {
match build.as_str() { match build.as_str() {
Some(s) => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(s)), Some(s) => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(s, None, optional)),
None => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(rule)), None => SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(rule, None, optional)),
} }
} }
} }
fn get_single_child(name: &str, rule: &str, build: &Yaml) -> ChildSpec { fn get_single_child(name: &str, rule: &str, optional: bool, build: &Yaml) -> ChildSpec {
ChildSpec::SingleChild(SingleChild::new( ChildSpec::SingleChild(SingleChild::new(
name, name,
rule, rule,
get_single_child_to_build(name, rule, build), get_single_child_to_build(name, rule, optional, build),
)) ))
} }
@ -92,18 +115,25 @@ fn get_child_specs(children: &Yaml) -> Vec<ChildSpec> {
.map(|(name, props)| (name.as_str().unwrap(), props)) .map(|(name, props)| (name.as_str().unwrap(), props))
.unwrap(); .unwrap();
let rule = props["rule"].as_str().unwrap(); let rule = props["rule"]
.as_str()
.map(|s| s.to_string())
.unwrap_or(name.to_case(Case::Pascal));
if get_skip(&props["skip"]) { if get_skip(&props["skip"]) {
return ChildSpec::SkipChild(SkipChild::new(name, rule)); return ChildSpec::SkipChild(SkipChild::new(name, &rule));
} }
let build = &props["build"]; let build = &props["build"];
if get_vec(&props["vec"]) { if get_vec(&props["vec"]) {
get_vec_child(name, rule, build) get_vec_child(name, &rule, build)
} else { } else {
get_single_child(name, rule, build) let optional = props["optional"]
.as_bool()
.unwrap_or_else(|| false);
get_single_child(name, &rule, optional, build)
} }
} else { } else {
ChildSpec::SingleChild(SingleChild::from_name_snake(child_spec.as_str().unwrap())) ChildSpec::SingleChild(SingleChild::from_name_snake(child_spec.as_str().unwrap()))

View File

@ -9,6 +9,7 @@ use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
use spec::BuildSpec; use spec::BuildSpec;
use syn::File; use syn::File;
use syn::spanned::Spanned;
fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) { fn debug_built_spec(build_spec: &BuildSpec, token_stream: &TokenStream) {
println!("*** BuildSpec ***"); println!("*** BuildSpec ***");

View File

@ -233,6 +233,8 @@ impl SingleChild {
rule: name.to_case(Case::Pascal), rule: name.to_case(Case::Pascal),
build: SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule( build: SingleChildToBuild::Type(SingleTypeChildToBuild::from_build_or_rule(
&name.to_case(Case::Pascal), &name.to_case(Case::Pascal),
None,
false,
)), )),
} }
} }
@ -272,14 +274,22 @@ pub struct SingleTypeChildToBuild {
build: String, build: String,
var_name: String, var_name: String,
with: String, with: String,
or_else: Option<String>,
optional: bool,
} }
impl SingleTypeChildToBuild { impl SingleTypeChildToBuild {
pub fn from_build_or_rule(build_or_rule: &str) -> Self { pub fn from_build_or_rule(
build_or_rule: &str,
or_else: Option<String>,
optional: bool,
) -> Self {
Self { Self {
build: build_or_rule.to_string(), build: build_or_rule.to_string(),
var_name: build_or_rule.to_case(Case::Snake), var_name: build_or_rule.to_case(Case::Snake),
with: make_build_fn_name(build_or_rule), with: make_build_fn_name(build_or_rule),
or_else,
optional,
} }
} }
@ -297,6 +307,16 @@ impl SingleTypeChildToBuild {
pub fn with(&self) -> &str { pub fn with(&self) -> &str {
&self.with &self.with
} }
/// The default fn to call when unwrapping the child (before passing as arg to new).
pub fn or_else(&self) -> Option<&str> {
self.or_else.as_deref()
}
/// If the type should be wrapped in an Option.
pub fn optional(&self) -> bool {
self.optional
}
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -64,9 +64,15 @@ fn handle_single_type_child(
let child_ident_mut = format_ident!("{}_mut", single_type_child.var_name()); let child_ident_mut = format_ident!("{}_mut", single_type_child.var_name());
let child_type_ident = format_ident!("{}", single_type_child.build()); let child_type_ident = format_ident!("{}", single_type_child.build());
member_names.push(child_ident.clone()); member_names.push(child_ident.clone());
if single_type_child.optional() {
annotated_members.push(quote! {
#child_ident: Option<Box<#child_type_ident>>
});
} else {
annotated_members.push(quote! { annotated_members.push(quote! {
#child_ident: Box<#child_type_ident> #child_ident: Box<#child_type_ident>
}); })
}
accessors.push(quote! { accessors.push(quote! {
pub fn #child_ident(&self) -> &#child_type_ident { pub fn #child_ident(&self) -> &#child_type_ident {
self.#child_ident.as_ref() self.#child_ident.as_ref()

View File

@ -0,0 +1,5 @@
use math::add
fn main()
println add(1, 2) // 3
end

View File

@ -0,0 +1,3 @@
mod math
pub fn add(a: Int, b: Int) = a + b

View File

@ -78,18 +78,32 @@ $defs:
properties: properties:
rule: rule:
type: string type: string
description: The type to build, in Pascal case.
optional:
type: boolean
description: If true, this child will be stored as an Option.
build: build:
oneOf: oneOf:
- type: string - type: string
- $ref: "#/$defs/SingleChildBuildDefinition" - $ref: "#/$defs/SingleChildBuildDefinition"
required:
- rule
SingleChildBuildDefinition: SingleChildBuildDefinition:
type: object type: object
additionalProperties: false additionalProperties: false
description: A definition of what exactly to build for a given child rule. description: A definition of what exactly to build for a given child rule.
oneOf: oneOf:
- $ref: "#/$defs/BuildSingleTypeChild"
- $ref: "#/$defs/BuildBooleanChild" - $ref: "#/$defs/BuildBooleanChild"
BuildSingleTypeChild:
type: object
additionalProperties: false
description: A definition of a single-type child to build.
properties:
or_else:
type: string
description: The method name to call upon the built-type if the rule is not found. Takes precedence over "or_else_default".
or_else_default:
type: boolean
description: Whether to call the default method on the built-type if the rule is not found.
BuildBooleanChild: BuildBooleanChild:
type: object type: object
additionalProperties: false additionalProperties: false

View File

@ -1,19 +1,21 @@
# $schema: ./ast.schema.yaml # $schema: ./ast.schema.yaml
# Top-level constructs
CompilationUnit: CompilationUnit:
children: children:
- namespace - parent_mod
- use_statements: - use_statements:
rule: UseStatement rule: UseStatement
vec: true vec: true
- module_level_declarations: - module_level_declarations:
rule: ModuleLevelDeclaration rule: ModuleLevelDeclaration
Namespace: vec: true
ParentMod:
children: children:
- ns_kw: - mod_kw:
rule: Ns rule: Mod
skip: true skip: true
- fqn: - fqn:
rule: Fqn rule: FullyQualifiedName
UseStatement: UseStatement:
children: children:
- use_kw: - use_kw:
@ -24,17 +26,49 @@ UseStatement:
vec: true vec: true
- suffix: - suffix:
rule: UseStatementSuffix rule: UseStatementSuffix
UseStatementPrefix:
children:
- identifier
UseStatementSuffix:
rules:
- Identifier
- rule: Star
build: UseStatementStarSuffix
- UseList
UseList:
children:
- identifiers:
rule: Identifier
vec: true
# Level declarations
ModuleLevelDeclaration: ModuleLevelDeclaration:
rules: rules:
- rule: Module - Module
build: ModuleDeclaration - Interface
- rule: Interface - Class
build: InterfaceDeclaration - Function
- rule: Class
build: ClassDeclaration
- FunctionDefinition
- PlatformFunction - PlatformFunction
ModuleDeclaration: InterfaceLevelDeclaration:
rules:
- CompanionModule
- Interface
- Class
- InterfaceFunction
- InterfaceDefaultFunction
- InterfaceOperatorFunction
- InterfaceDefaultOperatorFunction
ClassLevelDeclaration:
children:
- CompanionModule
- Interface
- Class
- Function
- OperatorFunction
- PlatformFunction
# Main organizational constructs
Module:
children: children:
- is_public: - is_public:
rule: Pub rule: Pub
@ -49,7 +83,47 @@ ModuleDeclaration:
- declarations: - declarations:
rule: ModuleLevelDeclaration rule: ModuleLevelDeclaration
vec: true vec: true
ClassDeclaration: - end_kw:
rule: End
skip: true
CompanionModule:
children:
- companion_kw:
rule: Companion
skip: true
- mod_kw:
rule: Mod
skip: true
- declarations:
rule: ModuleLevelDeclaration
vec: true
- end_kw:
rule: End
skip: true
Interface:
children:
- is_public:
rule: Pub
build:
type: boolean
on: rule_present
- int_kw:
rule: IntKw
skip: true
- identifier
- generic_parameters:
build:
or_else_default: true
- implements_list:
build:
or_else_default: true
- declarations:
rule: InterfaceLevelDeclaration
vec: true
- end_kw:
rule: End
skip: true
Class:
children: children:
- is_public: - is_public:
rule: Pub rule: Pub
@ -60,22 +134,27 @@ ClassDeclaration:
rule: ClassKw rule: ClassKw
skip: true skip: true
- identifier - identifier
- generic_parameters - generic_parameters:
- class_constructor build:
- implements_list or_else_default: true
- class_constructor:
build:
or_else_default: true
- implements_list:
build:
or_else_default: true
- class_level_declarations: - class_level_declarations:
rule: ClassLevelDeclaration rule: ClassLevelDeclaration
vec: true vec: true
FunctionDeclaration:
# Function constructs
Function:
children: children:
- is_public: - is_public:
rule: Pub rule: Pub
build: build:
type: boolean type: boolean
on: rule_present on: rule_present
- modifier:
rule: Modifier
build: FunctionModifier
- fn_kw: - fn_kw:
rule: Fn rule: Fn
skip: true skip: true
@ -83,5 +162,47 @@ FunctionDeclaration:
rule: GenericParameters rule: GenericParameters
- identifier - identifier
- parameters - parameters
- return_type - return_type:
build:
or_else: void
- function_body - function_body
OperatorFunction:
children:
- is_public:
rule: Pub
build:
type: boolean
on: rule_present
- op_kw:
rule: Op
skip: true
- generics:
rule: GenericParameters
build:
or_else_default: true
- operator
- parameters
- return_type:
build:
or_else: void
- function_body
PlatformFunction:
children:
- is_public:
rule: Pub
build:
type: boolean
on: rule_present
- platform_kw:
rule: Platform
skip: true
- fn_kw:
rule: Fn
skip: true
- generics:
rule: GenericParameters
build:
or_else_default: true
- identifier
- parameters
- return_type

View File

@ -30,6 +30,8 @@ Alias = { "alias" }
True = { "true" } True = { "true" }
False = { "false" } False = { "false" }
Use = { "use" } Use = { "use" }
End = { "end" }
Companion = { "comp" }
// Keywords: primitive types // Keywords: primitive types
Byte = { "Byte" } Byte = { "Byte" }
@ -322,22 +324,31 @@ RefList = {
CompilationUnit = { CompilationUnit = {
SOI SOI
~ ( Namespace ~ Semicolon )? ~ ParentMod?
~ ( UseStatement ~ Semicolon )* ~ ( UseStatement | ModuleLevelDeclaration )*
~ ModuleLevelDeclaration*
~ EOI ~ EOI
} }
Namespace = { ParentMod = {
Ns Mod
~ FullyQualifiedName ~ FullyQualifiedName
} }
UseStatement = { UseStatement = {
Use Use
~ Identifier ~ UseStatementPrefix*
~ ( "::" ~ Identifier )* ~ UseStatementSuffix
~ ( "::" ~ ( Star | UseList ) )? }
UseStatementPrefix = {
Identifier
~ "::"
}
UseStatementSuffix = {
Identifier
| Star
| UseList
} }
UseList = { UseList = {
@ -353,12 +364,12 @@ ModuleLevelDeclaration = {
Module Module
| Interface | Interface
| Class | Class
| FunctionDefinition | Function
| PlatformFunction | PlatformFunction
} }
InterfaceLevelDeclaration = { InterfaceLevelDeclaration = {
Module CompanionModule
| Interface | Interface
| Class | Class
| InterfaceFunction | InterfaceFunction
@ -368,14 +379,12 @@ InterfaceLevelDeclaration = {
} }
ClassLevelDeclaration = { ClassLevelDeclaration = {
Module CompanionModule
| Interface | Interface
| Class | Class
| FunctionDefinition | Function
| OperatorFunctionDefinition | OperatorFunction
| PlatformFunction | PlatformFunction
| Property
| Field
} }
// Main organizational constructs // Main organizational constructs
@ -384,7 +393,15 @@ Module = {
Pub? Pub?
~ Mod ~ Mod
~ Identifier ~ Identifier
~ "{" ~ ModuleLevelDeclaration* ~ "}" ~ ModuleLevelDeclaration*
~ End
}
CompanionModule = {
Companion
~ Mod
~ ModuleLevelDeclaration*
~ End
} }
Interface = { Interface = {
@ -393,7 +410,8 @@ Interface = {
~ Identifier ~ Identifier
~ GenericParameters? ~ GenericParameters?
~ ImplementsList? ~ ImplementsList?
~ ( "{" ~ InterfaceLevelDeclaration* ~ "}" )? ~ InterfaceLevelDeclaration*
~ End
} }
Class = { Class = {
@ -403,14 +421,14 @@ Class = {
~ GenericParameters? ~ GenericParameters?
~ ClassConstructor? ~ ClassConstructor?
~ ImplementsList? ~ ImplementsList?
~ ( "{" ~ ClassLevelDeclaration* ~ "}" )? ~ ClassLevelDeclaration*
~ End
} }
// Function constructs // Function constructs
FunctionDefinition = { Function = {
Pub? Pub?
~ FunctionModifier?
~ Fn ~ Fn
~ GenericParameters? ~ GenericParameters?
~ Identifier ~ Identifier
@ -419,9 +437,8 @@ FunctionDefinition = {
~ FunctionBody ~ FunctionBody
} }
OperatorFunctionDefinition = { OperatorFunction = {
Pub? Pub?
~ FunctionModifier?
~ Op ~ Op
~ GenericParameters? ~ GenericParameters?
~ Operator ~ Operator
@ -432,14 +449,12 @@ OperatorFunctionDefinition = {
PlatformFunction = { PlatformFunction = {
Pub? Pub?
~ FunctionModifier?
~ Platform ~ Platform
~ Fn ~ Fn
~ GenericParameters? ~ GenericParameters?
~ Identifier ~ Identifier
~ Parameters ~ Parameters
~ ReturnType ~ ReturnType
~ ";"
} }
InterfaceFunction = { InterfaceFunction = {
@ -482,13 +497,7 @@ InterfaceDefaultOperatorFunction = {
~ FunctionBody ~ FunctionBody
} }
FunctionModifier = { // Function Components
Static
| Cons
| Mut ~ Ref
| Mut
| Ref
}
FunctionBody = { FunctionBody = {
FunctionAliasBody FunctionAliasBody