forked from AbleOS/ableos_userland
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 = [
|
||||
"codespan-reporting",
|
||||
"derive_more",
|
||||
"itertools",
|
||||
"logos",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -174,6 +175,12 @@ dependencies = [
|
|||
"syn 1.0.105",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -229,6 +236,15 @@ dependencies = [
|
|||
"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]]
|
||||
name = "libc"
|
||||
version = "0.2.138"
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
codespan-reporting = "0.11.1"
|
||||
derive_more = "0.99.17"
|
||||
itertools = "0.10.5"
|
||||
logos = "0"
|
||||
proc-macro2 = "1.0.56"
|
||||
quote = "1.0.26"
|
||||
|
|
|
@ -4,7 +4,7 @@ The example implementation will be in rust
|
|||
|
||||
IDL | Rust
|
||||
__________
|
||||
boolean | bool
|
||||
Boolean | bool
|
||||
I8 | i8
|
||||
I16 | i16
|
||||
I32 | i32
|
||||
|
@ -15,8 +15,8 @@ U32 | u32
|
|||
U64 | u64
|
||||
F32 | f32
|
||||
F64 | f64
|
||||
Constant X Y Z | const X: Y = Z;
|
||||
Type | type
|
||||
Constant X = Make Y { Z } | const X: Y = Y { Z };
|
||||
Alias | type
|
||||
Vector<X> | Vec<X>
|
||||
Array[X;Y] | [X;Y]
|
||||
Function X accepts(YX) returns(ZX) | fn X(YX) -> ZX
|
||||
Array<X, Y> | [X; Y]
|
||||
Function X Takes(YX) Returns(ZX) | fn X(YX) -> ZX
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
Alias Byte = U8;
|
||||
Alias Int = U32;
|
||||
Alias String = Vector<Byte>;
|
||||
|
||||
Enumeration Boolean {
|
||||
False = 0,
|
||||
True = 1,
|
||||
}
|
||||
Alias Byte = u8;
|
||||
Alias Int = u32;
|
||||
|
||||
Enumeration Nothing {}
|
||||
|
||||
|
@ -14,6 +8,11 @@ Enumeration Option<T> {
|
|||
Some(T)
|
||||
}
|
||||
|
||||
Enumeration Result<T, E> {
|
||||
Ok(T),
|
||||
Err(E)
|
||||
}
|
||||
|
||||
Structure Version {
|
||||
major: 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,24 +1,26 @@
|
|||
Module vfs;
|
||||
// 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 {
|
||||
major: 1,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
major: 1,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
};
|
||||
|
||||
Alias Path = String;
|
||||
|
||||
Structure File {
|
||||
name: String,
|
||||
data: Vector<Byte>,
|
||||
name: String,
|
||||
data: Vector<Byte>,
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
Constant Version = Make Version {
|
||||
major: 1
|
||||
minor: 0
|
||||
patch: 0
|
||||
major: 1, minor: 0, patch: 0
|
||||
};
|
||||
|
||||
Interface Iface {
|
||||
Function hello Takes(Int Boolean) Returns(Int);
|
||||
Function hello Takes(Int, Boolean,) Returns(Int);
|
||||
}
|
||||
|
||||
Function a_free_function Returns(Boolean);
|
||||
|
||||
Structure Hello {
|
||||
world: Boolean prompt: Option<String>
|
||||
world: Boolean,
|
||||
prompt: Option<String>,
|
||||
}
|
||||
|
||||
Enumeration Reality {
|
||||
Dead(Boolean Boolean),
|
||||
Dead(Boolean, Boolean),
|
||||
Alive {
|
||||
health: Int
|
||||
dying: Boolean
|
||||
}
|
||||
health: Int,
|
||||
dying: Boolean,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use std::collections::HashMap;
|
|||
/// - items
|
||||
#[derive(Debug)]
|
||||
pub struct IDLModule {
|
||||
pub name: String,
|
||||
// why: only allow use before other items
|
||||
// parser will error if use is present in any other place
|
||||
pub uses: Vec<UseDecl>,
|
||||
|
@ -121,7 +122,7 @@ pub enum EnumerationContent {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct UseDecl {
|
||||
pub module: ModulePath,
|
||||
pub path: (String, Option<String>)
|
||||
}
|
||||
|
||||
#[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 quote::quote;
|
||||
use itertools::Itertools;
|
||||
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 {
|
||||
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)]
|
||||
pub enum Ident {
|
||||
#[token("Module")]
|
||||
#[display(fmt = "Module")]
|
||||
Module,
|
||||
#[token("Interface")]
|
||||
#[display(fmt = "Interface")]
|
||||
Interface,
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
#![feature(result_option_inspect)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(default_free_fn)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use std::{fmt::Display, path::Path, process::exit};
|
||||
|
||||
use ast::IDLModule;
|
||||
use codegen::generate;
|
||||
use codespan_reporting::{
|
||||
diagnostic::{Diagnostic, Label, Severity},
|
||||
files::SimpleFile,
|
||||
term::{
|
||||
emit,
|
||||
termcolor::{ColorSpec, StandardStream, StandardStreamLock},
|
||||
Config, Styles,
|
||||
termcolor::{StandardStream, StandardStreamLock},
|
||||
Config,
|
||||
},
|
||||
};
|
||||
use lexer::{NumberSuffix, Token};
|
||||
use logos::Logos;
|
||||
use parser::TokenIterator;
|
||||
|
||||
use crate::lexer::Spanned;
|
||||
|
||||
mod ast;
|
||||
mod codegen;
|
||||
mod lexer;
|
||||
mod parser;
|
||||
mod codegen;
|
||||
|
||||
//const TEST: &str = include_str!("../assets/why.idl");
|
||||
|
||||
fn precheck<N: Display + Clone, S: AsRef<str>>(
|
||||
writer: &mut StandardStreamLock<'_>,
|
||||
|
@ -68,10 +69,10 @@ fn precheck<N: Display + Clone, S: AsRef<str>>(
|
|||
Diagnostic::warning()
|
||||
.with_message("Potentially invalid use of an uppercased number type")
|
||||
.with_labels(vec![Label::primary((), span.0)])
|
||||
.with_notes(vec![format!(
|
||||
"Replace {ident} with {}",
|
||||
ident.to_lowercase()
|
||||
), "Code generation might fail".into()]),
|
||||
.with_notes(vec![
|
||||
format!("Replace {ident} with {}", ident.to_lowercase()),
|
||||
"Code generation might fail".into(),
|
||||
]),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -98,6 +99,9 @@ fn precheck<N: Display + Clone, S: AsRef<str>>(
|
|||
fn main() {
|
||||
let mut args = std::env::args();
|
||||
args.next().unwrap();
|
||||
|
||||
let mut ast: Option<IDLModule> = None;
|
||||
|
||||
if let Some(file) = args.next() {
|
||||
let path = Path::new(&file);
|
||||
let codespan_file = codespan_reporting::files::SimpleFile::new(
|
||||
|
@ -113,7 +117,10 @@ fn main() {
|
|||
precheck(&mut writer.lock(), &config, &codespan_file);
|
||||
|
||||
match parser::parse(codespan_file.source()) {
|
||||
Ok(ast) => println!("{:#?}", ast),
|
||||
Ok(ast_) => {
|
||||
println!("{:#?}", ast_);
|
||||
ast = Some(ast_);
|
||||
}
|
||||
Err(e) => {
|
||||
let msg = e.to_string();
|
||||
let label = match e {
|
||||
|
@ -145,6 +152,9 @@ fn main() {
|
|||
} else {
|
||||
eprintln!("No file given. Aborting.");
|
||||
}
|
||||
|
||||
let rust = generate(ast.unwrap());
|
||||
println!("{}", rust);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
|
|
@ -41,8 +41,12 @@ impl<'a> Parser<'a> {
|
|||
match self.tokens.peek()?.0 {
|
||||
Token::Ident(Ident::Other(_)) => {
|
||||
tuple.push(self.ask_type()?.0);
|
||||
if let Token::Comma = self.tokens.peek()?.0 {
|
||||
self.eat();
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Comma => {
|
||||
self.eat();
|
||||
}
|
||||
Token::RightParen => {}
|
||||
_ => return Err(self.expected("a comma or closing parentheses")),
|
||||
};
|
||||
}
|
||||
Token::RightParen => {
|
||||
|
@ -74,8 +78,12 @@ impl<'a> Parser<'a> {
|
|||
)?;
|
||||
|
||||
structure.insert(field_name, self.ask_type()?.0);
|
||||
if let Token::Comma = self.tokens.peek()?.0 {
|
||||
self.eat();
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Comma => {
|
||||
self.eat();
|
||||
}
|
||||
Token::RightCurly => {}
|
||||
_ => return Err(self.expected("a comma or closing curly braces")),
|
||||
};
|
||||
}
|
||||
Token::RightCurly => {
|
||||
|
@ -101,8 +109,12 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if let Spanned(Token::Comma, _) = self.tokens.peek()? {
|
||||
self.eat();
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Comma => {
|
||||
self.eat();
|
||||
}
|
||||
Token::RightCurly => {}
|
||||
_ => return Err(self.expected("a comma or closing curly braces")),
|
||||
}
|
||||
|
||||
variants.push(EnumerationVariant {
|
||||
|
|
|
@ -83,9 +83,11 @@ impl<'a> Parser<'a> {
|
|||
self.get_real(|token| matches!(token, Token::Colon), "a colon")?;
|
||||
let Spanned(value, _) = self.ask_expr()?;
|
||||
params.insert(ident, value);
|
||||
if let Token::Comma = self.tokens.peek()?.0 {
|
||||
self.eat();
|
||||
};
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Comma => self.eat(),
|
||||
Token::RightCurly => {},
|
||||
_ => return Err(self.expected("a comma or a closing curly brace"))
|
||||
}
|
||||
}
|
||||
Token::RightCurly => break,
|
||||
_ => return Err(self.expected("an identifier or a closing curly brace (`}`)")),
|
||||
|
|
|
@ -61,8 +61,12 @@ impl<'a> Parser<'a> {
|
|||
match peeked {
|
||||
Token::Ident(_) => {
|
||||
takes.push(self.ask_type()?.0);
|
||||
if let Token::Comma = self.tokens.peek()?.0 {
|
||||
self.eat();
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Comma => {
|
||||
self.eat();
|
||||
}
|
||||
Token::RightParen => {}
|
||||
_ => return Err(self.expected("a comma or closing parentheses")),
|
||||
};
|
||||
}
|
||||
Token::RightParen => {
|
||||
|
@ -78,7 +82,7 @@ impl<'a> Parser<'a> {
|
|||
Token::Ident(Ident::Returns) => {
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::LeftParen),
|
||||
"Opening parentheses",
|
||||
"opening parentheses",
|
||||
)?;
|
||||
|
||||
let Spanned(returns_, _) = self.ask_type()?;
|
||||
|
@ -87,7 +91,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::RightParen),
|
||||
"Closing parentheses",
|
||||
"closing parentheses",
|
||||
)?;
|
||||
|
||||
self.semi()?;
|
||||
|
|
|
@ -7,7 +7,7 @@ mod types;
|
|||
use logos::{Lexer, Logos};
|
||||
|
||||
use crate::{
|
||||
ast::{IDLModule, Item, ItemAlias, ItemConstant, ModulePath, UseDecl},
|
||||
ast::{IDLModule, Item, ItemAlias, ItemConstant, UseDecl},
|
||||
lexer::{Ident, Span, Spanned, Token},
|
||||
};
|
||||
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> {
|
||||
let Spanned(_, kSp) = self.get_real(
|
||||
|token| matches!(token, Token::Ident(Ident::Alias)),
|
||||
|
@ -203,19 +168,33 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn ask_use(&mut self) -> Result<Spanned<UseDecl>, ParserError> {
|
||||
let Spanned(_, kSp) = {
|
||||
let Spanned(_, span) = {
|
||||
match self.tokens.peek()? {
|
||||
Spanned(Token::Ident(Ident::Use), _) => Ok(self.tokens.next()?),
|
||||
_ => 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> {
|
||||
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: {
|
||||
let mut real = vec![];
|
||||
loop {
|
||||
|
|
|
@ -29,8 +29,12 @@ impl<'a> Parser<'a> {
|
|||
self.get_real(|token| matches!(token, Token::Colon), "a colon")?;
|
||||
let Spanned(value, _) = self.ask_type()?;
|
||||
fields.insert(ident, value);
|
||||
if let Token::Comma = self.tokens.peek()?.0 {
|
||||
self.eat();
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Comma => {
|
||||
self.eat();
|
||||
}
|
||||
Token::RightCurly => {}
|
||||
_ => return Err(self.expected("a comma or closing curly braces")),
|
||||
};
|
||||
}
|
||||
Token::RightCurly => break,
|
||||
|
|
|
@ -33,14 +33,22 @@ impl<'a> Parser<'a> {
|
|||
|
||||
args.push(Box::new(self.ask_type()?.0));
|
||||
|
||||
if let Spanned(Token::Comma, _) = self.tokens.peek()? {
|
||||
self.eat(); // skip comma, allow trailing comma
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Comma => self.eat(),
|
||||
Token::RightArrow => {}
|
||||
_ => return Err(self.expected("a comma or closing angle brackets")),
|
||||
};
|
||||
|
||||
loop {
|
||||
match self.tokens.peek()? {
|
||||
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, _) => {
|
||||
self.eat();
|
||||
|
|
Loading…
Reference in a new issue