enumerations
This commit is contained in:
parent
68a58e6a53
commit
9f36b7ef7f
|
@ -1,19 +1,21 @@
|
|||
Type Byte = U8;
|
||||
Type Int = U32;
|
||||
Type String = Vector<Byte>;
|
||||
Alias Byte = U8;
|
||||
Alias Int = U32;
|
||||
Alias String = Vector<Byte>;
|
||||
|
||||
Enumurate Boolean {
|
||||
Enumeration Boolean {
|
||||
False = 0,
|
||||
True = 1,
|
||||
}
|
||||
|
||||
Union Option<T>{
|
||||
None,
|
||||
Some<T>
|
||||
Enumeration Nothing {}
|
||||
|
||||
Enumeration Option<T> {
|
||||
None,
|
||||
Some(T)
|
||||
}
|
||||
|
||||
Structure Version {
|
||||
major: Byte,
|
||||
minor: Byte,
|
||||
patch: Byte,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,7 +5,25 @@ Constant Hi = "WHY???/\n";
|
|||
Alias Yo = Byte;
|
||||
|
||||
Constant Version = Make Version {
|
||||
major: 1,
|
||||
minor: 0,
|
||||
major: 1
|
||||
minor: 0
|
||||
patch: 0
|
||||
};
|
||||
|
||||
Interface Iface {
|
||||
Function hello Takes(Int Boolean) Returns(Int);
|
||||
}
|
||||
|
||||
Function a_free_function Returns(Boolean);
|
||||
|
||||
Structure Hello {
|
||||
world: Boolean prompt: Option<String>
|
||||
}
|
||||
|
||||
Enumeration Reality {
|
||||
Dead(Boolean Boolean),
|
||||
Alive {
|
||||
health: Int
|
||||
dying: Boolean
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,20 +17,60 @@ pub struct IDLModule {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum Item {
|
||||
_Interface(ItemInterface),
|
||||
Interface(ItemInterface),
|
||||
Alias(ItemAlias),
|
||||
Constant(ItemConstant),
|
||||
Function(Function),
|
||||
Structure(ItemStructure),
|
||||
Enumeration(ItemEnumeration)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Function {
|
||||
pub name: String,
|
||||
pub takes: Vec<Type>,
|
||||
pub returns: Type
|
||||
pub returns: Type,
|
||||
}
|
||||
|
||||
// why
|
||||
pub type Type = String;
|
||||
#[derive(Debug)]
|
||||
pub struct Type {
|
||||
pub name: String,
|
||||
pub arguments: TypeArguments,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn infer() -> Self {
|
||||
Self {
|
||||
name: String::from(INFER_TYPE),
|
||||
arguments: TypeArguments::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const NOTHING_TYPE: &str = "Nothing";
|
||||
pub const INFER_TYPE: &str = "_";
|
||||
|
||||
impl Default for Type {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: String::from(NOTHING_TYPE),
|
||||
arguments: TypeArguments::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub enum TypeArguments {
|
||||
/// TypeName
|
||||
#[default]
|
||||
None,
|
||||
/// TypeName<T1, T2, T3, TN>
|
||||
AngleBracketed(Vec<Box<Type>>),
|
||||
}
|
||||
|
||||
pub fn nothing() -> Type {
|
||||
Type::default()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ItemInterface {
|
||||
|
@ -38,16 +78,44 @@ pub struct ItemInterface {
|
|||
pub functions: Vec<Function>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ItemStructure {
|
||||
pub name: String,
|
||||
pub fields: HashMap<String, Type>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ItemAlias {
|
||||
pub name: String,
|
||||
pub referree: String,
|
||||
pub referree: Type,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ItemConstant {
|
||||
pub name: String,
|
||||
pub expr: Expr
|
||||
pub expr: Expr,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ItemEnumeration {
|
||||
pub name: String,
|
||||
pub arguments: TypeArguments,
|
||||
pub variants: Vec<EnumerationVariant>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EnumerationVariant {
|
||||
pub name: String,
|
||||
pub content: EnumerationContent
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub enum EnumerationContent {
|
||||
#[default]
|
||||
None,
|
||||
Tuple(Vec<Type>),
|
||||
Structure(HashMap<String, Type>),
|
||||
Value(NumberLiteral)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -59,20 +127,20 @@ pub struct UseDecl {
|
|||
pub enum Expr {
|
||||
Literal(Literal),
|
||||
_IdentAccess(String),
|
||||
Make(Box<ExprMake>)
|
||||
Make(Box<ExprMake>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExprMake {
|
||||
pub name: String,
|
||||
pub params: HashMap<String, Expr>
|
||||
pub params: HashMap<String, Expr>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Literal {
|
||||
String(String),
|
||||
Number(NumberLiteral),
|
||||
Char(char)
|
||||
Char(char),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{
|
||||
fmt::Display,
|
||||
ops::{Add, Range, AddAssign},
|
||||
ops::{Add, AddAssign, Range},
|
||||
};
|
||||
|
||||
use logos::Logos;
|
||||
|
@ -51,7 +51,10 @@ pub enum Token {
|
|||
#[regex(r#"(-)?\d+"#, |lex| lex.slice().parse().ok())]
|
||||
NumberLiteral(i64),
|
||||
|
||||
#[regex(r"(ptr|u8|i8|u16|i16|u32|i32|u64|i64|f32|f64)", |lex| NumberSuffix::lexer(lex.slice()).next().and_then(Result::ok))]
|
||||
#[regex(
|
||||
r"(ptr|u8|i8|u16|i16|u32|i32|u64|i64|f32|f64)",
|
||||
|lex| NumberSuffix::lexer(lex.slice()).next().and_then(Result::ok)
|
||||
)]
|
||||
NumberSuffix(NumberSuffix),
|
||||
|
||||
#[regex(r#"[a-zA-Z_][a-zA-Z\d_]*"#, |lex| Ident::lexer(lex.slice()).next().and_then(Result::ok))]
|
||||
|
@ -73,10 +76,18 @@ pub enum Ident {
|
|||
Structure,
|
||||
#[token("Alias")]
|
||||
Alias,
|
||||
#[token("Enumeration")]
|
||||
Enumeration,
|
||||
#[token("Use")]
|
||||
Use,
|
||||
#[token("Make")]
|
||||
Make,
|
||||
#[token("Takes")]
|
||||
Takes,
|
||||
#[token("Returns")]
|
||||
Returns,
|
||||
#[token("_")]
|
||||
Underscore,
|
||||
#[regex(r"[a-zA-Z_][a-zA-Z\d_]*", |lex| lex.slice().parse().ok())]
|
||||
Other(String),
|
||||
}
|
||||
|
|
|
@ -36,9 +36,15 @@ fn main() {
|
|||
parser::ParserError::UnexpectedEOF => Label::primary(
|
||||
(),
|
||||
(codespan_file.source().len() - 1)..codespan_file.source().len(),
|
||||
).with_message("Unexpected end of file here"),
|
||||
parser::ParserError::Unexpected(expected, Spanned(got, span)) => Label::primary((), span.0).with_message(format!("Unexpected `{got}`, expected {expected}")),
|
||||
parser::ParserError::PleaseStopParsingUse => unreachable!()
|
||||
)
|
||||
.with_message("Unexpected end of file here"),
|
||||
parser::ParserError::Unexpected(expected, Spanned(got, span)) => {
|
||||
Label::primary((), span.0)
|
||||
.with_message(format!("Unexpected `{got}`, expected {expected}"))
|
||||
}
|
||||
parser::ParserError::PleaseStopParsingUse => unsafe {
|
||||
std::hint::unreachable_unchecked()
|
||||
},
|
||||
};
|
||||
let diagnostic = codespan_reporting::diagnostic::Diagnostic::error()
|
||||
.with_message(msg)
|
||||
|
@ -52,6 +58,8 @@ fn main() {
|
|||
.unwrap();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!("No file given. Aborting.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
133
programs/aidl/src/parser/enumeration.rs
Normal file
133
programs/aidl/src/parser/enumeration.rs
Normal file
|
@ -0,0 +1,133 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
ast::{EnumerationContent, EnumerationVariant, ItemEnumeration, Type},
|
||||
lexer::{Ident, Spanned, Token},
|
||||
};
|
||||
|
||||
use super::{Parser, ParserError};
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn ask_enumeration(&mut self) -> Result<Spanned<ItemEnumeration>, ParserError> {
|
||||
let Spanned(_, span) = self.get_real(
|
||||
|token| matches!(token, Token::Ident(Ident::Enumeration)),
|
||||
"the `Enumeration` keyword",
|
||||
)?;
|
||||
|
||||
let Spanned(Type { name, arguments }, _) = self.ask_type()?;
|
||||
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::LeftCurly),
|
||||
"an opening curly brace",
|
||||
)?;
|
||||
|
||||
let mut variants = vec![];
|
||||
|
||||
loop {
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Ident(Ident::Other(_)) => {
|
||||
let Spanned(variant_name, _) = self.ask_ident()?;
|
||||
|
||||
let mut content = EnumerationContent::None;
|
||||
|
||||
loop {
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::LeftParen => {
|
||||
self.eat();
|
||||
|
||||
let mut tuple = vec![];
|
||||
|
||||
loop {
|
||||
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();
|
||||
};
|
||||
}
|
||||
Token::RightParen => {
|
||||
self.eat();
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return Err(
|
||||
self.expected("closing parentheses or a type")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
content = EnumerationContent::Tuple(tuple);
|
||||
}
|
||||
Token::LeftCurly => {
|
||||
self.eat();
|
||||
|
||||
let mut structure = HashMap::<String, Type>::new();
|
||||
|
||||
loop {
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Ident(Ident::Other(_)) => {
|
||||
let Spanned(field_name, _) = self.ask_ident()?;
|
||||
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::Colon),
|
||||
"a colon",
|
||||
)?;
|
||||
|
||||
structure.insert(field_name, self.ask_type()?.0);
|
||||
if let Token::Comma = self.tokens.peek()?.0 {
|
||||
self.eat();
|
||||
};
|
||||
}
|
||||
Token::RightCurly => {
|
||||
self.eat();
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return Err(
|
||||
self.expected("closing parentheses or a type")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
content = EnumerationContent::Structure(structure);
|
||||
}
|
||||
Token::Equals => {
|
||||
self.eat();
|
||||
|
||||
content = EnumerationContent::Value(self._ask_number_literal()?.0);
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
if let Spanned(Token::Comma, _) = self.tokens.peek()? {
|
||||
self.eat();
|
||||
}
|
||||
|
||||
variants.push(EnumerationVariant {
|
||||
name: variant_name,
|
||||
content,
|
||||
});
|
||||
}
|
||||
Token::RightCurly => break,
|
||||
_ => return Err(self.expected("a closing curly brace or a variant")),
|
||||
}
|
||||
}
|
||||
|
||||
if let Spanned(Token::RightCurly, _) = self.tokens.peek()? {
|
||||
self.eat();
|
||||
|
||||
return Ok(Spanned(
|
||||
ItemEnumeration {
|
||||
name,
|
||||
arguments,
|
||||
variants,
|
||||
},
|
||||
span + self.tokens.span(),
|
||||
));
|
||||
};
|
||||
|
||||
Err(self.expected("???"))
|
||||
}
|
||||
}
|
|
@ -17,26 +17,20 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
Token::Ident(Ident::Make) => {
|
||||
self.eat();
|
||||
self._ask_struct_init()?
|
||||
.map(Box::new)
|
||||
.map(Expr::Make)
|
||||
self._ask_struct_init()?.map(Box::new).map(Expr::Make)
|
||||
}
|
||||
_ => return Err(self.expected("an expression")),
|
||||
})
|
||||
}
|
||||
|
||||
fn _ask_literal(&mut self) -> Result<Spanned<Literal>, ParserError> {
|
||||
let Spanned(token, mut span) = self.tokens.next()?;
|
||||
Ok(match token {
|
||||
Token::StringLiteral(string) => Spanned(Literal::String(string), span),
|
||||
Token::CharLiteral(chr) => Spanned(Literal::Char(chr), span),
|
||||
Token::NumberLiteral(number) => {
|
||||
pub fn _ask_number_literal(&mut self) -> Result<Spanned<NumberLiteral>, ParserError> {
|
||||
match self.tokens.next()? {
|
||||
Spanned(Token::NumberLiteral(number), mut span) => {
|
||||
let lit = if let Spanned(Token::NumberSuffix(_), sp) = self.tokens.peek()? {
|
||||
span += sp;
|
||||
|
||||
use NumberLiteral::*;
|
||||
Literal::Number(
|
||||
match unwrap_match!(
|
||||
match unwrap_match!(
|
||||
self.tokens.next()?, Spanned(Token::NumberSuffix(suffering), _) => suffering) // eat suffix
|
||||
{
|
||||
NumberSuffix::Ptr => Ptr(number as usize),
|
||||
|
@ -49,14 +43,26 @@ impl<'a> Parser<'a> {
|
|||
NumberSuffix::U64 => U64(number as u64),
|
||||
NumberSuffix::I64 => I64(number),
|
||||
_ => return Err(self.expected("a non-floating number suffix"))
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Literal::Number(NumberLiteral::Infer(number))
|
||||
NumberLiteral::Infer(number)
|
||||
};
|
||||
|
||||
Spanned(lit, span)
|
||||
Ok(Spanned(lit, span))
|
||||
}
|
||||
_ => Err(self.expected("a number literal")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _ask_literal(&mut self) -> Result<Spanned<Literal>, ParserError> {
|
||||
if let Spanned(Token::NumberLiteral(_), _) = self.tokens.peek()? {
|
||||
return Ok(self._ask_number_literal()?.map(Literal::Number));
|
||||
};
|
||||
let Spanned(token, span) = self.tokens.next()?;
|
||||
Ok(match token {
|
||||
Token::StringLiteral(string) => Spanned(Literal::String(string), span),
|
||||
Token::CharLiteral(chr) => Spanned(Literal::Char(chr), span),
|
||||
|
||||
_ => return Err(self.expected("a literal")),
|
||||
})
|
||||
}
|
||||
|
@ -90,6 +96,6 @@ impl<'a> Parser<'a> {
|
|||
return Ok(Spanned(ExprMake { name, params }, nSp + ccSp));
|
||||
};
|
||||
|
||||
Err(self.expected("something"))
|
||||
Err(self.expected("closing curly braces"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
use crate::{
|
||||
ast::{nothing, Function, ItemInterface},
|
||||
lexer::{Ident, Span, Spanned, Token},
|
||||
};
|
||||
|
||||
use super::{Parser, ParserError};
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn ask_interface(&mut self) -> Result<Spanned<ItemInterface>, ParserError> {
|
||||
// Interface
|
||||
let Spanned(_, mut span) = self.get_real(
|
||||
|token| matches!(token, Token::Ident(Ident::Interface)),
|
||||
"the `Interface` keyword",
|
||||
)?;
|
||||
// InterfaceName
|
||||
let Spanned(name, _) = self.ask_ident()?;
|
||||
|
||||
// {
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::LeftCurly),
|
||||
"opening curly brackets",
|
||||
)?;
|
||||
|
||||
let mut functions = vec![];
|
||||
|
||||
loop {
|
||||
match self.tokens.peek()? {
|
||||
Spanned(Token::RightCurly, end) => {
|
||||
self.eat();
|
||||
span += end;
|
||||
break;
|
||||
}
|
||||
Spanned(Token::Ident(Ident::Function), _) => functions.push(self.ask_function()?.0),
|
||||
_ => return Err(self.expected("A function or closing curly braces")),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Spanned(ItemInterface { name, functions }, span))
|
||||
}
|
||||
|
||||
pub fn ask_function(&mut self) -> Result<Spanned<Function>, ParserError> {
|
||||
let Spanned(_, bsp) = self.get_real(
|
||||
|token| matches!(token, Token::Ident(Ident::Function)),
|
||||
"the `Function` keyword",
|
||||
)?;
|
||||
|
||||
let Spanned(name, _) = self.ask_ident()?;
|
||||
|
||||
let Spanned(next, esp) = self.tokens.next()?;
|
||||
match next {
|
||||
Token::Ident(Ident::Takes) => {
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::LeftParen),
|
||||
"Opening parentheses",
|
||||
)?;
|
||||
|
||||
let mut takes = vec![];
|
||||
let mut returns = nothing();
|
||||
loop {
|
||||
let Spanned(peeked, _) = self.tokens.peek()?;
|
||||
match peeked {
|
||||
Token::Ident(_) => {
|
||||
takes.push(self.ask_type()?.0);
|
||||
if let Token::Comma = self.tokens.peek()?.0 {
|
||||
self.eat();
|
||||
};
|
||||
}
|
||||
Token::RightParen => {
|
||||
self.eat();
|
||||
break;
|
||||
}
|
||||
_ => return Err(self.expected("closing parentheses or a type name")),
|
||||
}
|
||||
}
|
||||
|
||||
match self.tokens.next()?.0 {
|
||||
Token::Semicolon => {}
|
||||
Token::Ident(Ident::Returns) => {
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::LeftParen),
|
||||
"Opening parentheses",
|
||||
)?;
|
||||
|
||||
let Spanned(returns_, _) = self.ask_type()?;
|
||||
|
||||
returns = returns_;
|
||||
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::RightParen),
|
||||
"Closing parentheses",
|
||||
)?;
|
||||
|
||||
self.semi()?;
|
||||
}
|
||||
_ => return Err(self.expected("a semicolon or a Returns clause")),
|
||||
}
|
||||
|
||||
Ok(Spanned(
|
||||
Function {
|
||||
name,
|
||||
takes,
|
||||
returns,
|
||||
},
|
||||
bsp + Span(self.tokens.lexer.span()),
|
||||
))
|
||||
}
|
||||
Token::Ident(Ident::Returns) => {
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::LeftParen),
|
||||
"Opening parentheses",
|
||||
)?;
|
||||
|
||||
let Spanned(returns, _) = self.ask_type()?;
|
||||
|
||||
self.get_real(
|
||||
|token| matches!(token, Token::RightParen),
|
||||
"Closing parentheses",
|
||||
)?;
|
||||
|
||||
Ok(Spanned(
|
||||
Function {
|
||||
name,
|
||||
takes: Vec::new(),
|
||||
returns,
|
||||
},
|
||||
bsp + self.semi()?,
|
||||
))
|
||||
}
|
||||
Token::Semicolon => Ok(Spanned(
|
||||
Function {
|
||||
name,
|
||||
takes: Vec::new(),
|
||||
returns: nothing(),
|
||||
},
|
||||
bsp + esp,
|
||||
)),
|
||||
_ => Err(self.expected("a Takes clause, a Returns clause or a semicolon")),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
mod enumeration;
|
||||
mod expr;
|
||||
mod interface;
|
||||
mod structure;
|
||||
mod types;
|
||||
|
||||
use logos::{Lexer, Logos};
|
||||
|
||||
use crate::{
|
||||
ast::{IDLModule, Item, ItemAlias, ItemConstant, ItemInterface, ModulePath, UseDecl},
|
||||
ast::{IDLModule, Item, ItemAlias, ItemConstant, ModulePath, UseDecl},
|
||||
lexer::{Ident, Span, Spanned, Token},
|
||||
};
|
||||
use std::iter::Iterator;
|
||||
|
@ -52,7 +54,11 @@ impl<'a> TokenIterator<'a> {
|
|||
}
|
||||
|
||||
pub fn current(&self) -> Spanned<String> {
|
||||
Spanned(self.lexer.slice().to_owned(), Span(self.lexer.span()))
|
||||
Spanned(self.lexer.slice().to_owned(), self.span())
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
Span(self.lexer.span())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,11 +100,16 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn ask_ident(&mut self) -> Result<Spanned<String>, ParserError> {
|
||||
Ok(crate::unwrap_match!(
|
||||
self.get_real(|token| matches!(token, Token::Ident(Ident::Other(_))), "an identifier")?,
|
||||
Spanned(Token::Ident(Ident::Other(ident)), span) =>
|
||||
Spanned(ident, span)
|
||||
))
|
||||
Ok(
|
||||
match self.get_real(
|
||||
|token| matches!(token, Token::Ident(Ident::Other(_) | Ident::Underscore)),
|
||||
"an identifier",
|
||||
)? {
|
||||
Spanned(Token::Ident(Ident::Other(ident)), span) => Spanned(ident, span),
|
||||
Spanned(Token::Ident(Ident::Underscore), span) => Spanned("_".to_owned(), span),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn ask_modpath(
|
||||
|
@ -115,18 +126,18 @@ impl<'a> Parser<'a> {
|
|||
Spanned(Token::Ident(Ident::Other(ident)), span_span)
|
||||
if !in_path_seg && waiting_next_seg =>
|
||||
{
|
||||
span = span + span_span;
|
||||
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_span;
|
||||
span += span_span;
|
||||
waiting_next_seg = true;
|
||||
in_path_seg = false;
|
||||
}
|
||||
v if end(&v.0) && (in_path_seg || !waiting_next_seg) => {
|
||||
span = span + v.1;
|
||||
span += v.1;
|
||||
break;
|
||||
}
|
||||
_ => return Err(self.expected("a path segment")),
|
||||
|
@ -136,22 +147,6 @@ impl<'a> Parser<'a> {
|
|||
Ok(Spanned(ModulePath { segments }, span))
|
||||
}
|
||||
|
||||
fn _ask_interface(&mut self) -> Result<Spanned<ItemInterface>, ParserError> {
|
||||
let Spanned(_, kSp) = self.get_real(
|
||||
|token| matches!(token, Token::Ident(Ident::Interface)),
|
||||
"`Interface`",
|
||||
)?;
|
||||
let Spanned(ident, iSp) = self.ask_ident()?;
|
||||
|
||||
Ok(Spanned::new(
|
||||
ItemInterface {
|
||||
name: ident,
|
||||
functions: vec![],
|
||||
},
|
||||
[kSp, iSp, self.semi()?],
|
||||
))
|
||||
}
|
||||
|
||||
fn ask_alias(&mut self) -> Result<Spanned<ItemAlias>, ParserError> {
|
||||
let Spanned(_, kSp) = self.get_real(
|
||||
|token| matches!(token, Token::Ident(Ident::Alias)),
|
||||
|
@ -160,7 +155,7 @@ impl<'a> Parser<'a> {
|
|||
let Spanned(name, nSp) = self.ask_ident()?;
|
||||
|
||||
let Spanned(_, eqSp) = self.get_real(|token| matches!(token, Token::Equals), "`=`")?;
|
||||
let Spanned(referree, rSp) = self.ask_ident()?;
|
||||
let Spanned(referree, rSp) = self.ask_type()?;
|
||||
|
||||
Ok(Spanned::new(
|
||||
ItemAlias { name, referree },
|
||||
|
@ -177,7 +172,10 @@ impl<'a> Parser<'a> {
|
|||
let Spanned(_, eqSp) = self.get_real(|token| matches!(token, Token::Equals), "`=`")?;
|
||||
let Spanned(expr, exprSp) = self.ask_expr()?;
|
||||
|
||||
Ok(Spanned::new(ItemConstant { name, expr }, [kSp, nSp, eqSp, exprSp, self.semi()?]))
|
||||
Ok(Spanned::new(
|
||||
ItemConstant { name, expr },
|
||||
[kSp, nSp, eqSp, exprSp, self.semi()?],
|
||||
))
|
||||
}
|
||||
|
||||
fn ask_item(&mut self) -> Result<Spanned<Item>, ParserError> {
|
||||
|
@ -186,10 +184,13 @@ impl<'a> Parser<'a> {
|
|||
Err(self.expected("a keyword, not just an identifier"))?
|
||||
}
|
||||
Token::Ident(keyword) => match keyword {
|
||||
//Ident::Interface => self.ask_interface()?.map(Item::Interface),
|
||||
Ident::Interface => self.ask_interface()?.map(Item::Interface),
|
||||
Ident::Structure => self.ask_structure()?.map(Item::Structure),
|
||||
Ident::Alias => self.ask_alias()?.map(Item::Alias),
|
||||
Ident::Constant => self.ask_constant()?.map(Item::Constant),
|
||||
_ => Err(self.expected("`Alias` or `Constant`"))?,
|
||||
Ident::Function => self.ask_function()?.map(Item::Function),
|
||||
Ident::Enumeration => self.ask_enumeration()?.map(Item::Enumeration),
|
||||
_ => Err(self.expected("an item denoting keyword (Interface, Structure, Alias, Constant, Function, Enumeration)"))?,
|
||||
},
|
||||
_ => Err(self.expected("a keyword"))?,
|
||||
})
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{lexer::{Ident, Spanned, Token}, ast::{Type, ItemStructure}};
|
||||
|
||||
use super::{Parser, ParserError};
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn ask_structure(&mut self) -> Result<Spanned<ItemStructure>, ParserError> {
|
||||
let Spanned(_, span) = self.get_real(
|
||||
|token| matches!(token, Token::Ident(Ident::Structure)),
|
||||
"the `Structure` keyword",
|
||||
)?;
|
||||
|
||||
let Spanned(name, _) = self.ask_ident()?;
|
||||
let Spanned(_, _) = self.get_real(
|
||||
|token| matches!(token, Token::LeftCurly),
|
||||
"an opening curly brace (`{`)",
|
||||
)?;
|
||||
|
||||
let mut fields = HashMap::<String, Type>::new();
|
||||
|
||||
loop {
|
||||
match self.tokens.peek()?.0 {
|
||||
Token::Ident(_) => {
|
||||
let Spanned(ident, _) = self.ask_ident().unwrap();
|
||||
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();
|
||||
};
|
||||
}
|
||||
Token::RightCurly => break,
|
||||
_ => return Err(self.expected("an identifier or a closing curly brace (`}`)")),
|
||||
}
|
||||
}
|
||||
|
||||
if let Spanned(Token::RightCurly, end) = self.tokens.next()? {
|
||||
return Ok(Spanned(ItemStructure { name, fields }, span + end));
|
||||
};
|
||||
|
||||
Err(self.expected("closing curly braces"))
|
||||
}
|
||||
}
|
45
programs/aidl/src/parser/types.rs
Normal file
45
programs/aidl/src/parser/types.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use crate::{
|
||||
ast::{Type, TypeArguments, INFER_TYPE},
|
||||
lexer::{Spanned, Token},
|
||||
};
|
||||
|
||||
use super::{Parser, ParserError};
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn ask_type(&mut self) -> Result<Spanned<Type>, ParserError> {
|
||||
let Spanned(name, span) = self.ask_ident()?;
|
||||
|
||||
if name == INFER_TYPE {
|
||||
return Ok(Spanned(Type::infer(), span));
|
||||
}
|
||||
|
||||
let mut arguments = TypeArguments::None;
|
||||
|
||||
if let Spanned(crate::lexer::Token::LeftArrow, _) = self.tokens.peek()? {
|
||||
self.eat(); // eat `<`
|
||||
|
||||
let mut args = vec![];
|
||||
|
||||
args.push(Box::new(self.ask_type()?.0));
|
||||
|
||||
if let Spanned(Token::Comma, _) = self.tokens.peek()? {
|
||||
self.eat(); // skip comma, allow trailing comma
|
||||
};
|
||||
|
||||
loop {
|
||||
match self.tokens.peek()? {
|
||||
Spanned(Token::Ident(_), _) => args.push(Box::new(self.ask_type()?.0)),
|
||||
Spanned(Token::RightArrow, _) => {
|
||||
self.eat();
|
||||
break;
|
||||
}
|
||||
_ => return Err(self.expected("closing angle brackets or a type name")),
|
||||
}
|
||||
}
|
||||
|
||||
arguments = TypeArguments::AngleBracketed(args);
|
||||
};
|
||||
|
||||
Ok(Spanned(Type { name, arguments }, span + self.tokens.span()))
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue