enumerations
This commit is contained in:
parent
68a58e6a53
commit
9f36b7ef7f
|
@ -1,19 +1,21 @@
|
||||||
Type Byte = U8;
|
Alias Byte = U8;
|
||||||
Type Int = U32;
|
Alias Int = U32;
|
||||||
Type String = Vector<Byte>;
|
Alias String = Vector<Byte>;
|
||||||
|
|
||||||
Enumurate Boolean {
|
Enumeration Boolean {
|
||||||
False = 0,
|
False = 0,
|
||||||
True = 1,
|
True = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
Union Option<T>{
|
Enumeration Nothing {}
|
||||||
|
|
||||||
|
Enumeration Option<T> {
|
||||||
None,
|
None,
|
||||||
Some<T>
|
Some(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
Structure Version {
|
Structure Version {
|
||||||
major: Byte,
|
major: Byte,
|
||||||
minor: Byte,
|
minor: Byte,
|
||||||
patch: Byte,
|
patch: Byte,
|
||||||
};
|
}
|
||||||
|
|
|
@ -5,7 +5,25 @@ Constant Hi = "WHY???/\n";
|
||||||
Alias Yo = Byte;
|
Alias Yo = Byte;
|
||||||
|
|
||||||
Constant Version = Make Version {
|
Constant Version = Make Version {
|
||||||
major: 1,
|
major: 1
|
||||||
minor: 0,
|
minor: 0
|
||||||
patch: 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)]
|
#[derive(Debug)]
|
||||||
pub enum Item {
|
pub enum Item {
|
||||||
_Interface(ItemInterface),
|
Interface(ItemInterface),
|
||||||
Alias(ItemAlias),
|
Alias(ItemAlias),
|
||||||
Constant(ItemConstant),
|
Constant(ItemConstant),
|
||||||
|
Function(Function),
|
||||||
|
Structure(ItemStructure),
|
||||||
|
Enumeration(ItemEnumeration)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub takes: Vec<Type>,
|
pub takes: Vec<Type>,
|
||||||
pub returns: Type
|
pub returns: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
// why
|
#[derive(Debug)]
|
||||||
pub type Type = String;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct ItemInterface {
|
pub struct ItemInterface {
|
||||||
|
@ -38,16 +78,44 @@ pub struct ItemInterface {
|
||||||
pub functions: Vec<Function>,
|
pub functions: Vec<Function>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ItemStructure {
|
||||||
|
pub name: String,
|
||||||
|
pub fields: HashMap<String, Type>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ItemAlias {
|
pub struct ItemAlias {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub referree: String,
|
pub referree: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ItemConstant {
|
pub struct ItemConstant {
|
||||||
pub name: String,
|
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)]
|
#[derive(Debug)]
|
||||||
|
@ -59,20 +127,20 @@ pub struct UseDecl {
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
_IdentAccess(String),
|
_IdentAccess(String),
|
||||||
Make(Box<ExprMake>)
|
Make(Box<ExprMake>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ExprMake {
|
pub struct ExprMake {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub params: HashMap<String, Expr>
|
pub params: HashMap<String, Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
String(String),
|
String(String),
|
||||||
Number(NumberLiteral),
|
Number(NumberLiteral),
|
||||||
Char(char)
|
Char(char),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
ops::{Add, Range, AddAssign},
|
ops::{Add, AddAssign, Range},
|
||||||
};
|
};
|
||||||
|
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
|
@ -51,7 +51,10 @@ pub enum Token {
|
||||||
#[regex(r#"(-)?\d+"#, |lex| lex.slice().parse().ok())]
|
#[regex(r#"(-)?\d+"#, |lex| lex.slice().parse().ok())]
|
||||||
NumberLiteral(i64),
|
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),
|
NumberSuffix(NumberSuffix),
|
||||||
|
|
||||||
#[regex(r#"[a-zA-Z_][a-zA-Z\d_]*"#, |lex| Ident::lexer(lex.slice()).next().and_then(Result::ok))]
|
#[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,
|
Structure,
|
||||||
#[token("Alias")]
|
#[token("Alias")]
|
||||||
Alias,
|
Alias,
|
||||||
|
#[token("Enumeration")]
|
||||||
|
Enumeration,
|
||||||
#[token("Use")]
|
#[token("Use")]
|
||||||
Use,
|
Use,
|
||||||
#[token("Make")]
|
#[token("Make")]
|
||||||
Make,
|
Make,
|
||||||
|
#[token("Takes")]
|
||||||
|
Takes,
|
||||||
|
#[token("Returns")]
|
||||||
|
Returns,
|
||||||
|
#[token("_")]
|
||||||
|
Underscore,
|
||||||
#[regex(r"[a-zA-Z_][a-zA-Z\d_]*", |lex| lex.slice().parse().ok())]
|
#[regex(r"[a-zA-Z_][a-zA-Z\d_]*", |lex| lex.slice().parse().ok())]
|
||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,15 @@ fn main() {
|
||||||
parser::ParserError::UnexpectedEOF => Label::primary(
|
parser::ParserError::UnexpectedEOF => Label::primary(
|
||||||
(),
|
(),
|
||||||
(codespan_file.source().len() - 1)..codespan_file.source().len(),
|
(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}")),
|
.with_message("Unexpected end of file here"),
|
||||||
parser::ParserError::PleaseStopParsingUse => unreachable!()
|
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()
|
let diagnostic = codespan_reporting::diagnostic::Diagnostic::error()
|
||||||
.with_message(msg)
|
.with_message(msg)
|
||||||
|
@ -52,6 +58,8 @@ fn main() {
|
||||||
.unwrap();
|
.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,25 +17,19 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
Token::Ident(Ident::Make) => {
|
Token::Ident(Ident::Make) => {
|
||||||
self.eat();
|
self.eat();
|
||||||
self._ask_struct_init()?
|
self._ask_struct_init()?.map(Box::new).map(Expr::Make)
|
||||||
.map(Box::new)
|
|
||||||
.map(Expr::Make)
|
|
||||||
}
|
}
|
||||||
_ => return Err(self.expected("an expression")),
|
_ => return Err(self.expected("an expression")),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _ask_literal(&mut self) -> Result<Spanned<Literal>, ParserError> {
|
pub fn _ask_number_literal(&mut self) -> Result<Spanned<NumberLiteral>, ParserError> {
|
||||||
let Spanned(token, mut span) = self.tokens.next()?;
|
match self.tokens.next()? {
|
||||||
Ok(match token {
|
Spanned(Token::NumberLiteral(number), mut span) => {
|
||||||
Token::StringLiteral(string) => Spanned(Literal::String(string), span),
|
|
||||||
Token::CharLiteral(chr) => Spanned(Literal::Char(chr), span),
|
|
||||||
Token::NumberLiteral(number) => {
|
|
||||||
let lit = if let Spanned(Token::NumberSuffix(_), sp) = self.tokens.peek()? {
|
let lit = if let Spanned(Token::NumberSuffix(_), sp) = self.tokens.peek()? {
|
||||||
span += sp;
|
span += sp;
|
||||||
|
|
||||||
use NumberLiteral::*;
|
use NumberLiteral::*;
|
||||||
Literal::Number(
|
|
||||||
match unwrap_match!(
|
match unwrap_match!(
|
||||||
self.tokens.next()?, Spanned(Token::NumberSuffix(suffering), _) => suffering) // eat suffix
|
self.tokens.next()?, Spanned(Token::NumberSuffix(suffering), _) => suffering) // eat suffix
|
||||||
{
|
{
|
||||||
|
@ -49,14 +43,26 @@ impl<'a> Parser<'a> {
|
||||||
NumberSuffix::U64 => U64(number as u64),
|
NumberSuffix::U64 => U64(number as u64),
|
||||||
NumberSuffix::I64 => I64(number),
|
NumberSuffix::I64 => I64(number),
|
||||||
_ => return Err(self.expected("a non-floating number suffix"))
|
_ => return Err(self.expected("a non-floating number suffix"))
|
||||||
},
|
}
|
||||||
)
|
|
||||||
} else {
|
} 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")),
|
_ => return Err(self.expected("a literal")),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -90,6 +96,6 @@ impl<'a> Parser<'a> {
|
||||||
return Ok(Spanned(ExprMake { name, params }, nSp + ccSp));
|
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 expr;
|
||||||
mod interface;
|
mod interface;
|
||||||
mod structure;
|
mod structure;
|
||||||
|
mod types;
|
||||||
|
|
||||||
use logos::{Lexer, Logos};
|
use logos::{Lexer, Logos};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{IDLModule, Item, ItemAlias, ItemConstant, ItemInterface, ModulePath, UseDecl},
|
ast::{IDLModule, Item, ItemAlias, ItemConstant, ModulePath, UseDecl},
|
||||||
lexer::{Ident, Span, Spanned, Token},
|
lexer::{Ident, Span, Spanned, Token},
|
||||||
};
|
};
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
@ -52,7 +54,11 @@ impl<'a> TokenIterator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current(&self) -> Spanned<String> {
|
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> {
|
fn ask_ident(&mut self) -> Result<Spanned<String>, ParserError> {
|
||||||
Ok(crate::unwrap_match!(
|
Ok(
|
||||||
self.get_real(|token| matches!(token, Token::Ident(Ident::Other(_))), "an identifier")?,
|
match self.get_real(
|
||||||
Spanned(Token::Ident(Ident::Other(ident)), span) =>
|
|token| matches!(token, Token::Ident(Ident::Other(_) | Ident::Underscore)),
|
||||||
Spanned(ident, span)
|
"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(
|
fn ask_modpath(
|
||||||
|
@ -115,18 +126,18 @@ impl<'a> Parser<'a> {
|
||||||
Spanned(Token::Ident(Ident::Other(ident)), span_span)
|
Spanned(Token::Ident(Ident::Other(ident)), span_span)
|
||||||
if !in_path_seg && waiting_next_seg =>
|
if !in_path_seg && waiting_next_seg =>
|
||||||
{
|
{
|
||||||
span = span + span_span;
|
span += span_span;
|
||||||
segments.push(ident);
|
segments.push(ident);
|
||||||
in_path_seg = true;
|
in_path_seg = true;
|
||||||
waiting_next_seg = false;
|
waiting_next_seg = false;
|
||||||
}
|
}
|
||||||
Spanned(Token::Dot, span_span) if in_path_seg && !waiting_next_seg => {
|
Spanned(Token::Dot, span_span) if in_path_seg && !waiting_next_seg => {
|
||||||
span = span + span_span;
|
span += span_span;
|
||||||
waiting_next_seg = true;
|
waiting_next_seg = true;
|
||||||
in_path_seg = false;
|
in_path_seg = false;
|
||||||
}
|
}
|
||||||
v if end(&v.0) && (in_path_seg || !waiting_next_seg) => {
|
v if end(&v.0) && (in_path_seg || !waiting_next_seg) => {
|
||||||
span = span + v.1;
|
span += v.1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_ => return Err(self.expected("a path segment")),
|
_ => return Err(self.expected("a path segment")),
|
||||||
|
@ -136,22 +147,6 @@ impl<'a> Parser<'a> {
|
||||||
Ok(Spanned(ModulePath { segments }, span))
|
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> {
|
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)),
|
||||||
|
@ -160,7 +155,7 @@ impl<'a> Parser<'a> {
|
||||||
let Spanned(name, nSp) = self.ask_ident()?;
|
let Spanned(name, nSp) = self.ask_ident()?;
|
||||||
|
|
||||||
let Spanned(_, eqSp) = self.get_real(|token| matches!(token, Token::Equals), "`=`")?;
|
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(
|
Ok(Spanned::new(
|
||||||
ItemAlias { name, referree },
|
ItemAlias { name, referree },
|
||||||
|
@ -177,7 +172,10 @@ impl<'a> Parser<'a> {
|
||||||
let Spanned(_, eqSp) = self.get_real(|token| matches!(token, Token::Equals), "`=`")?;
|
let Spanned(_, eqSp) = self.get_real(|token| matches!(token, Token::Equals), "`=`")?;
|
||||||
let Spanned(expr, exprSp) = self.ask_expr()?;
|
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> {
|
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"))?
|
Err(self.expected("a keyword, not just an identifier"))?
|
||||||
}
|
}
|
||||||
Token::Ident(keyword) => match keyword {
|
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::Alias => self.ask_alias()?.map(Item::Alias),
|
||||||
Ident::Constant => self.ask_constant()?.map(Item::Constant),
|
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"))?,
|
_ => 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