aaaaaaa
This commit is contained in:
parent
59aad853a0
commit
d97b3e3636
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -37,6 +37,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
"itertools",
|
||||||
"logos",
|
"logos",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -174,6 +175,12 @@ dependencies = [
|
||||||
"syn 1.0.105",
|
"syn 1.0.105",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
@ -229,6 +236,15 @@ dependencies = [
|
||||||
"hashbrown 0.12.3",
|
"hashbrown 0.12.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.138"
|
version = "0.2.138"
|
||||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codespan-reporting = "0.11.1"
|
codespan-reporting = "0.11.1"
|
||||||
derive_more = "0.99.17"
|
derive_more = "0.99.17"
|
||||||
|
itertools = "0.10.5"
|
||||||
logos = "0"
|
logos = "0"
|
||||||
proc-macro2 = "1.0.56"
|
proc-macro2 = "1.0.56"
|
||||||
quote = "1.0.26"
|
quote = "1.0.26"
|
||||||
|
|
|
@ -4,7 +4,7 @@ The example implementation will be in rust
|
||||||
|
|
||||||
IDL | Rust
|
IDL | Rust
|
||||||
__________
|
__________
|
||||||
boolean | bool
|
Boolean | bool
|
||||||
I8 | i8
|
I8 | i8
|
||||||
I16 | i16
|
I16 | i16
|
||||||
I32 | i32
|
I32 | i32
|
||||||
|
@ -15,8 +15,8 @@ U32 | u32
|
||||||
U64 | u64
|
U64 | u64
|
||||||
F32 | f32
|
F32 | f32
|
||||||
F64 | f64
|
F64 | f64
|
||||||
Constant X Y Z | const X: Y = Z;
|
Constant X = Make Y { Z } | const X: Y = Y { Z };
|
||||||
Type | type
|
Alias | type
|
||||||
Vector<X> | Vec<X>
|
Vector<X> | Vec<X>
|
||||||
Array[X;Y] | [X;Y]
|
Array<X, Y> | [X; Y]
|
||||||
Function X accepts(YX) returns(ZX) | fn X(YX) -> ZX
|
Function X Takes(YX) Returns(ZX) | fn X(YX) -> ZX
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
Alias Byte = U8;
|
Alias Byte = u8;
|
||||||
Alias Int = U32;
|
Alias Int = u32;
|
||||||
Alias String = Vector<Byte>;
|
|
||||||
|
|
||||||
Enumeration Boolean {
|
|
||||||
False = 0,
|
|
||||||
True = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
Enumeration Nothing {}
|
Enumeration Nothing {}
|
||||||
|
|
||||||
|
@ -14,6 +8,11 @@ Enumeration Option<T> {
|
||||||
Some(T)
|
Some(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Enumeration Result<T, E> {
|
||||||
|
Ok(T),
|
||||||
|
Err(E)
|
||||||
|
}
|
||||||
|
|
||||||
Structure Version {
|
Structure Version {
|
||||||
major: Byte,
|
major: Byte,
|
||||||
minor: Byte,
|
minor: Byte,
|
||||||
|
|
21
programs/aidl/assets/core.rs
Normal file
21
programs/aidl/assets/core.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#![crate_name = "aidl_core"]
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
#![no_implicit_prelude]
|
||||||
|
|
||||||
|
extern crate core as rust_core;
|
||||||
|
extern crate alloc as rust_alloc;
|
||||||
|
|
||||||
|
pub use self::rust_core::{option::Option, result::Result};
|
||||||
|
pub use self::rust_alloc::{vec::Vec as Vector, string::String};
|
||||||
|
|
||||||
|
pub type Nothing = ();
|
||||||
|
|
||||||
|
pub type Byte = u8;
|
||||||
|
pub type Int = u32;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Version {
|
||||||
|
pub major: Byte,
|
||||||
|
pub minor: Byte,
|
||||||
|
pub patch: Byte
|
||||||
|
}
|
BIN
programs/aidl/assets/libaidl_core.rlib
Normal file
BIN
programs/aidl/assets/libaidl_core.rlib
Normal file
Binary file not shown.
BIN
programs/aidl/assets/libaidl_vfs.rlib
Normal file
BIN
programs/aidl/assets/libaidl_vfs.rlib
Normal file
Binary file not shown.
6
programs/aidl/assets/moves.idl
Normal file
6
programs/aidl/assets/moves.idl
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Interface Thing {
|
||||||
|
Function moves Takes(Move Self) Returns(Self);
|
||||||
|
|
||||||
|
Function immut_ref Takes(Reference Self);
|
||||||
|
Function mut_ref Takes(Mutable Reference Self);
|
||||||
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
|
Module vfs;
|
||||||
// core provides lots of useful types like String and Byte
|
// core provides lots of useful types like String and Byte
|
||||||
Use core;
|
Use core.Version;
|
||||||
|
Use core.Vector;
|
||||||
|
Use core.String;
|
||||||
|
|
||||||
Constant VERSION = Make Version {
|
Constant VERSION = Make Version {
|
||||||
major: 1,
|
major: 1,
|
||||||
|
@ -15,10 +18,9 @@ Structure File {
|
||||||
}
|
}
|
||||||
|
|
||||||
Interface File {
|
Interface File {
|
||||||
Function new Takes(Path) Returns(None);
|
Function create Takes(Path) Returns(Nothing);
|
||||||
|
|
||||||
// Open in this iteration assumes the file exists
|
|
||||||
Function open Takes(Path) Returns(File);
|
Function open Takes(Path) Returns(File);
|
||||||
|
|
||||||
Function close Takes(File) Returns(None);
|
Function close Takes(File) Returns(Nothing);
|
||||||
}
|
}
|
||||||
|
|
26
programs/aidl/assets/vfs.rs
Normal file
26
programs/aidl/assets/vfs.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#![crate_name = "aidl_vfs"]
|
||||||
|
#![crate_type = "rlib"]
|
||||||
|
#![no_implicit_prelude]
|
||||||
|
extern crate aidl_core;
|
||||||
|
|
||||||
|
use aidl_core::{Vector, Version, String};
|
||||||
|
|
||||||
|
pub const VERSION: Version = Version {
|
||||||
|
major: 1,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type Path = String;
|
||||||
|
|
||||||
|
pub struct FFile {
|
||||||
|
pub name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait File {
|
||||||
|
fn fields(&self) -> &FFile;
|
||||||
|
fn fields_mut(&mut self) -> &mut FFile;
|
||||||
|
fn into_fields(self) -> FFile where Self: Sized;
|
||||||
|
|
||||||
|
fn new(path: Path) -> Self;
|
||||||
|
}
|
|
@ -5,25 +5,24 @@ Constant Hi = "WHY???/\n";
|
||||||
Alias Yo = Byte;
|
Alias Yo = Byte;
|
||||||
|
|
||||||
Constant Version = Make Version {
|
Constant Version = Make Version {
|
||||||
major: 1
|
major: 1, minor: 0, patch: 0
|
||||||
minor: 0
|
|
||||||
patch: 0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Interface Iface {
|
Interface Iface {
|
||||||
Function hello Takes(Int Boolean) Returns(Int);
|
Function hello Takes(Int, Boolean,) Returns(Int);
|
||||||
}
|
}
|
||||||
|
|
||||||
Function a_free_function Returns(Boolean);
|
Function a_free_function Returns(Boolean);
|
||||||
|
|
||||||
Structure Hello {
|
Structure Hello {
|
||||||
world: Boolean prompt: Option<String>
|
world: Boolean,
|
||||||
|
prompt: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
Enumeration Reality {
|
Enumeration Reality {
|
||||||
Dead(Boolean Boolean),
|
Dead(Boolean, Boolean),
|
||||||
Alive {
|
Alive {
|
||||||
health: Int
|
health: Int,
|
||||||
dying: Boolean
|
dying: Boolean,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use std::collections::HashMap;
|
||||||
/// - items
|
/// - items
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IDLModule {
|
pub struct IDLModule {
|
||||||
|
pub name: String,
|
||||||
// why: only allow use before other items
|
// why: only allow use before other items
|
||||||
// parser will error if use is present in any other place
|
// parser will error if use is present in any other place
|
||||||
pub uses: Vec<UseDecl>,
|
pub uses: Vec<UseDecl>,
|
||||||
|
@ -121,7 +122,7 @@ pub enum EnumerationContent {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct UseDecl {
|
pub struct UseDecl {
|
||||||
pub module: ModulePath,
|
pub path: (String, Option<String>)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,10 +1,130 @@
|
||||||
use std::path::Path;
|
use std::default::default;
|
||||||
|
|
||||||
use crate::ast::IDLModule;
|
use crate::{ast::{IDLModule, ItemInterface, TypeArguments, Type}, unwrap_match};
|
||||||
|
|
||||||
use proc_macro2::{TokenStream, Ident, Span};
|
use itertools::Itertools;
|
||||||
use quote::quote;
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
|
use quote::{quote, ToTokens};
|
||||||
|
use syn::{Attribute, ItemExternCrate, ItemTrait, ItemUse, LitStr, Meta, Path, UsePath, Generics, punctuated::Punctuated, TypeArray, LitInt};
|
||||||
|
|
||||||
|
fn attr_inner(meta: Meta) -> Attribute {
|
||||||
|
Attribute {
|
||||||
|
pound_token: default(),
|
||||||
|
style: syn::AttrStyle::Inner(default()),
|
||||||
|
bracket_token: default(),
|
||||||
|
meta,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attr_just(name: &'static str) -> Attribute {
|
||||||
|
attr_inner(Meta::Path(Path::from(Ident::new(name, Span::call_site()))))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attr_inner_eq(name: &'static str, expr: &str) -> Attribute {
|
||||||
|
attr_inner(Meta::NameValue(syn::MetaNameValue {
|
||||||
|
path: Path::from(Ident::new(name, Span::call_site())),
|
||||||
|
eq_token: default(),
|
||||||
|
value: syn::Expr::Lit(syn::ExprLit {
|
||||||
|
attrs: vec![],
|
||||||
|
lit: syn::Lit::Str(LitStr::new(expr, Span::call_site())),
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extern_crate(name: &str) -> ItemExternCrate {
|
||||||
|
ItemExternCrate {
|
||||||
|
attrs: vec![],
|
||||||
|
vis: syn::Visibility::Inherited,
|
||||||
|
extern_token: default(),
|
||||||
|
crate_token: default(),
|
||||||
|
ident: Ident::new(name, Span::call_site()),
|
||||||
|
rename: None,
|
||||||
|
semi_token: default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_use(a: &str, b: &str) -> ItemUse {
|
||||||
|
ItemUse {
|
||||||
|
attrs: vec![],
|
||||||
|
vis: syn::Visibility::Inherited,
|
||||||
|
use_token: default(),
|
||||||
|
tree: syn::UseTree::Path(UsePath {
|
||||||
|
tree: Box::new(syn::UseTree::Name(syn::UseName {
|
||||||
|
ident: Ident::new(b, Span::call_site()),
|
||||||
|
})),
|
||||||
|
ident: Ident::new(a, Span::call_site()),
|
||||||
|
colon2_token: default(),
|
||||||
|
}),
|
||||||
|
semi_token: default(),
|
||||||
|
leading_colon: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gen_type(ty: Type) -> syn::Type {
|
||||||
|
fn make_array(mut args: Vec<Box<Type>>) -> TypeArray {
|
||||||
|
let box arity = args.pop().unwrap();
|
||||||
|
let box real = args.pop().unwrap();
|
||||||
|
|
||||||
|
drop(args);
|
||||||
|
|
||||||
|
TypeArray { bracket_token: default(), elem: Box::new(gen_type(real)), semi_token: default(), len: syn::Expr::Lit(syn::ExprLit { attrs: vec![], lit: syn::Lit::Int(LitInt::new(&arity.name, Span::call_site())) }) }
|
||||||
|
}
|
||||||
|
match ty.name.as_str() {
|
||||||
|
"Array" => syn::Type::Array(make_array(unwrap_match!(ty.arguments, TypeArguments::AngleBracketed(angle) => angle))),
|
||||||
|
name => syn::Type::Path(syn::TypePath { qself: None, path: Path::from(Ident::new(name, Span::call_site())) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn gen_iface(interface: ItemInterface) -> ItemTrait {
|
||||||
|
// ItemTrait {
|
||||||
|
// attrs: default(),
|
||||||
|
// vis: syn::Visibility::Public(default()),
|
||||||
|
// unsafety: None,
|
||||||
|
// auto_token: None,
|
||||||
|
// restriction: None,
|
||||||
|
// trait_token: default(),
|
||||||
|
// ident: Ident::new(&interface.name, Span::call_site()),
|
||||||
|
// generics: ,
|
||||||
|
// colon_token: (),
|
||||||
|
// supertraits: (),
|
||||||
|
// brace_token: (),
|
||||||
|
// items: (),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn generate(module: IDLModule) -> TokenStream {
|
pub fn generate(module: IDLModule) -> TokenStream {
|
||||||
quote! {}
|
let name = String::from("aidl_") + &module.name;
|
||||||
|
let attrs: TokenStream = [
|
||||||
|
attr_inner_eq("crate_name", &name),
|
||||||
|
attr_inner_eq("crate_type", "rlib"),
|
||||||
|
attr_just("no_implicit_prelude"),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(ToTokens::into_token_stream)
|
||||||
|
.collect();
|
||||||
|
let uses: Vec<_> = module
|
||||||
|
.uses
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| a.path)
|
||||||
|
.map(|(a, b)| (String::from("aidl_") + &a, b)) // aidl_core.Something
|
||||||
|
.collect();
|
||||||
|
let extern_crates: TokenStream = uses
|
||||||
|
.iter()
|
||||||
|
.map(|(a, _)| a.as_str())
|
||||||
|
.unique()
|
||||||
|
.map(extern_crate)
|
||||||
|
.map(ToTokens::into_token_stream)
|
||||||
|
.collect();
|
||||||
|
let use_defs: TokenStream = uses
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(ref a, ref b)| b.as_ref().map(|b| make_use(a.as_str(), b.as_str())))
|
||||||
|
.map(ToTokens::into_token_stream)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#attrs
|
||||||
|
|
||||||
|
#extern_crates
|
||||||
|
#use_defs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,9 @@ pub enum Token {
|
||||||
|
|
||||||
#[derive(Logos, Debug, Clone, PartialEq, Eq, derive_more::Display)]
|
#[derive(Logos, Debug, Clone, PartialEq, Eq, derive_more::Display)]
|
||||||
pub enum Ident {
|
pub enum Ident {
|
||||||
|
#[token("Module")]
|
||||||
|
#[display(fmt = "Module")]
|
||||||
|
Module,
|
||||||
#[token("Interface")]
|
#[token("Interface")]
|
||||||
#[display(fmt = "Interface")]
|
#[display(fmt = "Interface")]
|
||||||
Interface,
|
Interface,
|
||||||
|
|
|
@ -1,29 +1,30 @@
|
||||||
#![feature(result_option_inspect)]
|
#![feature(result_option_inspect)]
|
||||||
|
#![feature(box_patterns)]
|
||||||
|
#![feature(default_free_fn)]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use std::{fmt::Display, path::Path, process::exit};
|
use std::{fmt::Display, path::Path, process::exit};
|
||||||
|
|
||||||
|
use ast::IDLModule;
|
||||||
|
use codegen::generate;
|
||||||
use codespan_reporting::{
|
use codespan_reporting::{
|
||||||
diagnostic::{Diagnostic, Label, Severity},
|
diagnostic::{Diagnostic, Label, Severity},
|
||||||
files::SimpleFile,
|
files::SimpleFile,
|
||||||
term::{
|
term::{
|
||||||
emit,
|
emit,
|
||||||
termcolor::{ColorSpec, StandardStream, StandardStreamLock},
|
termcolor::{StandardStream, StandardStreamLock},
|
||||||
Config, Styles,
|
Config,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lexer::{NumberSuffix, Token};
|
use lexer::{NumberSuffix, Token};
|
||||||
use logos::Logos;
|
|
||||||
use parser::TokenIterator;
|
use parser::TokenIterator;
|
||||||
|
|
||||||
use crate::lexer::Spanned;
|
use crate::lexer::Spanned;
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
|
mod codegen;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod codegen;
|
|
||||||
|
|
||||||
//const TEST: &str = include_str!("../assets/why.idl");
|
|
||||||
|
|
||||||
fn precheck<N: Display + Clone, S: AsRef<str>>(
|
fn precheck<N: Display + Clone, S: AsRef<str>>(
|
||||||
writer: &mut StandardStreamLock<'_>,
|
writer: &mut StandardStreamLock<'_>,
|
||||||
|
@ -68,10 +69,10 @@ fn precheck<N: Display + Clone, S: AsRef<str>>(
|
||||||
Diagnostic::warning()
|
Diagnostic::warning()
|
||||||
.with_message("Potentially invalid use of an uppercased number type")
|
.with_message("Potentially invalid use of an uppercased number type")
|
||||||
.with_labels(vec![Label::primary((), span.0)])
|
.with_labels(vec![Label::primary((), span.0)])
|
||||||
.with_notes(vec![format!(
|
.with_notes(vec![
|
||||||
"Replace {ident} with {}",
|
format!("Replace {ident} with {}", ident.to_lowercase()),
|
||||||
ident.to_lowercase()
|
"Code generation might fail".into(),
|
||||||
), "Code generation might fail".into()]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -98,6 +99,9 @@ fn precheck<N: Display + Clone, S: AsRef<str>>(
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut args = std::env::args();
|
let mut args = std::env::args();
|
||||||
args.next().unwrap();
|
args.next().unwrap();
|
||||||
|
|
||||||
|
let mut ast: Option<IDLModule> = None;
|
||||||
|
|
||||||
if let Some(file) = args.next() {
|
if let Some(file) = args.next() {
|
||||||
let path = Path::new(&file);
|
let path = Path::new(&file);
|
||||||
let codespan_file = codespan_reporting::files::SimpleFile::new(
|
let codespan_file = codespan_reporting::files::SimpleFile::new(
|
||||||
|
@ -113,7 +117,10 @@ fn main() {
|
||||||
precheck(&mut writer.lock(), &config, &codespan_file);
|
precheck(&mut writer.lock(), &config, &codespan_file);
|
||||||
|
|
||||||
match parser::parse(codespan_file.source()) {
|
match parser::parse(codespan_file.source()) {
|
||||||
Ok(ast) => println!("{:#?}", ast),
|
Ok(ast_) => {
|
||||||
|
println!("{:#?}", ast_);
|
||||||
|
ast = Some(ast_);
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let msg = e.to_string();
|
let msg = e.to_string();
|
||||||
let label = match e {
|
let label = match e {
|
||||||
|
@ -145,6 +152,9 @@ fn main() {
|
||||||
} else {
|
} else {
|
||||||
eprintln!("No file given. Aborting.");
|
eprintln!("No file given. Aborting.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let rust = generate(ast.unwrap());
|
||||||
|
println!("{}", rust);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|
|
@ -41,8 +41,12 @@ impl<'a> Parser<'a> {
|
||||||
match self.tokens.peek()?.0 {
|
match self.tokens.peek()?.0 {
|
||||||
Token::Ident(Ident::Other(_)) => {
|
Token::Ident(Ident::Other(_)) => {
|
||||||
tuple.push(self.ask_type()?.0);
|
tuple.push(self.ask_type()?.0);
|
||||||
if let Token::Comma = self.tokens.peek()?.0 {
|
match self.tokens.peek()?.0 {
|
||||||
|
Token::Comma => {
|
||||||
self.eat();
|
self.eat();
|
||||||
|
}
|
||||||
|
Token::RightParen => {}
|
||||||
|
_ => return Err(self.expected("a comma or closing parentheses")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Token::RightParen => {
|
Token::RightParen => {
|
||||||
|
@ -74,8 +78,12 @@ impl<'a> Parser<'a> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
structure.insert(field_name, self.ask_type()?.0);
|
structure.insert(field_name, self.ask_type()?.0);
|
||||||
if let Token::Comma = self.tokens.peek()?.0 {
|
match self.tokens.peek()?.0 {
|
||||||
|
Token::Comma => {
|
||||||
self.eat();
|
self.eat();
|
||||||
|
}
|
||||||
|
Token::RightCurly => {}
|
||||||
|
_ => return Err(self.expected("a comma or closing curly braces")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Token::RightCurly => {
|
Token::RightCurly => {
|
||||||
|
@ -101,9 +109,13 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Spanned(Token::Comma, _) = self.tokens.peek()? {
|
match self.tokens.peek()?.0 {
|
||||||
|
Token::Comma => {
|
||||||
self.eat();
|
self.eat();
|
||||||
}
|
}
|
||||||
|
Token::RightCurly => {}
|
||||||
|
_ => return Err(self.expected("a comma or closing curly braces")),
|
||||||
|
}
|
||||||
|
|
||||||
variants.push(EnumerationVariant {
|
variants.push(EnumerationVariant {
|
||||||
name: variant_name,
|
name: variant_name,
|
||||||
|
|
|
@ -83,9 +83,11 @@ impl<'a> Parser<'a> {
|
||||||
self.get_real(|token| matches!(token, Token::Colon), "a colon")?;
|
self.get_real(|token| matches!(token, Token::Colon), "a colon")?;
|
||||||
let Spanned(value, _) = self.ask_expr()?;
|
let Spanned(value, _) = self.ask_expr()?;
|
||||||
params.insert(ident, value);
|
params.insert(ident, value);
|
||||||
if let Token::Comma = self.tokens.peek()?.0 {
|
match self.tokens.peek()?.0 {
|
||||||
self.eat();
|
Token::Comma => self.eat(),
|
||||||
};
|
Token::RightCurly => {},
|
||||||
|
_ => return Err(self.expected("a comma or a closing curly brace"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Token::RightCurly => break,
|
Token::RightCurly => break,
|
||||||
_ => return Err(self.expected("an identifier or a closing curly brace (`}`)")),
|
_ => return Err(self.expected("an identifier or a closing curly brace (`}`)")),
|
||||||
|
|
|
@ -61,8 +61,12 @@ impl<'a> Parser<'a> {
|
||||||
match peeked {
|
match peeked {
|
||||||
Token::Ident(_) => {
|
Token::Ident(_) => {
|
||||||
takes.push(self.ask_type()?.0);
|
takes.push(self.ask_type()?.0);
|
||||||
if let Token::Comma = self.tokens.peek()?.0 {
|
match self.tokens.peek()?.0 {
|
||||||
|
Token::Comma => {
|
||||||
self.eat();
|
self.eat();
|
||||||
|
}
|
||||||
|
Token::RightParen => {}
|
||||||
|
_ => return Err(self.expected("a comma or closing parentheses")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Token::RightParen => {
|
Token::RightParen => {
|
||||||
|
@ -78,7 +82,7 @@ impl<'a> Parser<'a> {
|
||||||
Token::Ident(Ident::Returns) => {
|
Token::Ident(Ident::Returns) => {
|
||||||
self.get_real(
|
self.get_real(
|
||||||
|token| matches!(token, Token::LeftParen),
|
|token| matches!(token, Token::LeftParen),
|
||||||
"Opening parentheses",
|
"opening parentheses",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let Spanned(returns_, _) = self.ask_type()?;
|
let Spanned(returns_, _) = self.ask_type()?;
|
||||||
|
@ -87,7 +91,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
self.get_real(
|
self.get_real(
|
||||||
|token| matches!(token, Token::RightParen),
|
|token| matches!(token, Token::RightParen),
|
||||||
"Closing parentheses",
|
"closing parentheses",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.semi()?;
|
self.semi()?;
|
||||||
|
|
|
@ -7,7 +7,7 @@ mod types;
|
||||||
use logos::{Lexer, Logos};
|
use logos::{Lexer, Logos};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{IDLModule, Item, ItemAlias, ItemConstant, ModulePath, UseDecl},
|
ast::{IDLModule, Item, ItemAlias, ItemConstant, UseDecl},
|
||||||
lexer::{Ident, Span, Spanned, Token},
|
lexer::{Ident, Span, Spanned, Token},
|
||||||
};
|
};
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
@ -118,41 +118,6 @@ impl<'a> Parser<'a> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ask_modpath(
|
|
||||||
&mut self,
|
|
||||||
end: impl Fn(&Token) -> bool,
|
|
||||||
) -> Result<Spanned<ModulePath>, ParserError> {
|
|
||||||
let mut segments = vec![];
|
|
||||||
let mut in_path_seg = false;
|
|
||||||
let mut waiting_next_seg = true;
|
|
||||||
let mut span = Span::ZERO;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match self.tokens.next()? {
|
|
||||||
Spanned(Token::Ident(Ident::Other(ident)), span_span)
|
|
||||||
if !in_path_seg && waiting_next_seg =>
|
|
||||||
{
|
|
||||||
span += span_span;
|
|
||||||
segments.push(ident);
|
|
||||||
in_path_seg = true;
|
|
||||||
waiting_next_seg = false;
|
|
||||||
}
|
|
||||||
Spanned(Token::Dot, span_span) if in_path_seg && !waiting_next_seg => {
|
|
||||||
span += span_span;
|
|
||||||
waiting_next_seg = true;
|
|
||||||
in_path_seg = false;
|
|
||||||
}
|
|
||||||
v if end(&v.0) && (in_path_seg || !waiting_next_seg) => {
|
|
||||||
span += v.1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => return Err(self.expected("a path segment")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Spanned(ModulePath { segments }, span))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ask_alias(&mut self) -> Result<Spanned<ItemAlias>, ParserError> {
|
fn ask_alias(&mut self) -> Result<Spanned<ItemAlias>, ParserError> {
|
||||||
let Spanned(_, kSp) = self.get_real(
|
let Spanned(_, kSp) = self.get_real(
|
||||||
|token| matches!(token, Token::Ident(Ident::Alias)),
|
|token| matches!(token, Token::Ident(Ident::Alias)),
|
||||||
|
@ -203,19 +168,33 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ask_use(&mut self) -> Result<Spanned<UseDecl>, ParserError> {
|
fn ask_use(&mut self) -> Result<Spanned<UseDecl>, ParserError> {
|
||||||
let Spanned(_, kSp) = {
|
let Spanned(_, span) = {
|
||||||
match self.tokens.peek()? {
|
match self.tokens.peek()? {
|
||||||
Spanned(Token::Ident(Ident::Use), _) => Ok(self.tokens.next()?),
|
Spanned(Token::Ident(Ident::Use), _) => Ok(self.tokens.next()?),
|
||||||
_ => Err(ParserError::PleaseStopParsingUse),
|
_ => Err(ParserError::PleaseStopParsingUse),
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
let Spanned(module, nSp) = self.ask_modpath(|token| matches!(token, Token::Semicolon))?;
|
let mut path = (self.ask_ident()?.0, None);
|
||||||
|
|
||||||
Ok(Spanned::new(UseDecl { module }, [kSp, nSp]))
|
if let Token::Dot = self.tokens.peek()?.0 {
|
||||||
|
self.eat();
|
||||||
|
path.1 = Some(self.ask_ident()?.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Spanned::new(UseDecl { path }, [span, self.semi()?]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(mut self) -> Result<IDLModule, ParserError> {
|
pub fn parse(mut self) -> Result<IDLModule, ParserError> {
|
||||||
Ok(IDLModule {
|
Ok(IDLModule {
|
||||||
|
name: {
|
||||||
|
self.get_real(
|
||||||
|
|token| matches!(token, Token::Ident(Ident::Module)),
|
||||||
|
"the `Module` keyword",
|
||||||
|
)?;
|
||||||
|
let name = self.ask_ident()?.0;
|
||||||
|
self.semi()?;
|
||||||
|
name
|
||||||
|
},
|
||||||
uses: {
|
uses: {
|
||||||
let mut real = vec![];
|
let mut real = vec![];
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -29,8 +29,12 @@ impl<'a> Parser<'a> {
|
||||||
self.get_real(|token| matches!(token, Token::Colon), "a colon")?;
|
self.get_real(|token| matches!(token, Token::Colon), "a colon")?;
|
||||||
let Spanned(value, _) = self.ask_type()?;
|
let Spanned(value, _) = self.ask_type()?;
|
||||||
fields.insert(ident, value);
|
fields.insert(ident, value);
|
||||||
if let Token::Comma = self.tokens.peek()?.0 {
|
match self.tokens.peek()?.0 {
|
||||||
|
Token::Comma => {
|
||||||
self.eat();
|
self.eat();
|
||||||
|
}
|
||||||
|
Token::RightCurly => {}
|
||||||
|
_ => return Err(self.expected("a comma or closing curly braces")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Token::RightCurly => break,
|
Token::RightCurly => break,
|
||||||
|
|
|
@ -33,14 +33,22 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
args.push(Box::new(self.ask_type()?.0));
|
args.push(Box::new(self.ask_type()?.0));
|
||||||
|
|
||||||
if let Spanned(Token::Comma, _) = self.tokens.peek()? {
|
match self.tokens.peek()?.0 {
|
||||||
self.eat(); // skip comma, allow trailing comma
|
Token::Comma => self.eat(),
|
||||||
|
Token::RightArrow => {}
|
||||||
|
_ => return Err(self.expected("a comma or closing angle brackets")),
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.tokens.peek()? {
|
match self.tokens.peek()? {
|
||||||
Spanned(Token::Ident(_) | Token::NumberLiteral(_), _) => {
|
Spanned(Token::Ident(_) | Token::NumberLiteral(_), _) => {
|
||||||
args.push(Box::new(self.ask_type()?.0))
|
args.push(Box::new(self.ask_type()?.0));
|
||||||
|
|
||||||
|
match self.tokens.peek()?.0 {
|
||||||
|
Token::Comma => self.eat(),
|
||||||
|
Token::RightArrow => {}
|
||||||
|
_ => return Err(self.expected("a comma or closing angle brackets")),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Spanned(Token::RightArrow, _) => {
|
Spanned(Token::RightArrow, _) => {
|
||||||
self.eat();
|
self.eat();
|
||||||
|
|
Loading…
Reference in a new issue