Import statement syntax
This commit is contained in:
parent
603ea89b98
commit
a054de56a2
@ -58,7 +58,8 @@ pub struct Statement {
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum StatementKind {
|
||||
Expression(Expression),
|
||||
Declaration(Declaration), //TODO Declaration should also be Meta-wrapped; only Expression and Declaration are Meta-wrapped maybe?
|
||||
Declaration(Declaration),
|
||||
Import(ImportSpecifier),
|
||||
}
|
||||
|
||||
pub type Block = Vec<Statement>;
|
||||
@ -272,3 +273,20 @@ pub enum ForBody {
|
||||
MonadicReturn(Expression),
|
||||
StatementBlock(Block),
|
||||
}
|
||||
|
||||
#[derive(Debug, Derivative, Clone)]
|
||||
#[derivative(PartialEq)]
|
||||
pub struct ImportSpecifier {
|
||||
#[derivative(PartialEq="ignore")]
|
||||
pub id: ItemId,
|
||||
pub path_components: Vec<Rc<String>>,
|
||||
pub imported_names: ImportedNames
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum ImportedNames {
|
||||
All,
|
||||
LastOfPath,
|
||||
List(Vec<Rc<String>>)
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,8 @@
|
||||
//! ```
|
||||
//! ## Imports
|
||||
//! ```text
|
||||
//! import := 'import'
|
||||
//! import := 'import' IDENTIFIER (:: IDENTIFIER)* import_suffix
|
||||
//! import_suffix := ε | '::{' IDENTIFIER (, IDENTIFIER)* '}' | '*' //TODO add qualified, exclusions, etc.
|
||||
//! ```
|
||||
mod test;
|
||||
|
||||
@ -351,6 +352,7 @@ impl Parser {
|
||||
Keyword(Let) => self.binding_declaration().map(|decl| StatementKind::Declaration(decl)),
|
||||
Keyword(Interface) => self.interface_declaration().map(|decl| StatementKind::Declaration(decl)),
|
||||
Keyword(Impl) => self.impl_declaration().map(|decl| StatementKind::Declaration(decl)),
|
||||
Keyword(Import) => self.import_declaration().map(|spec| StatementKind::Import(spec)),
|
||||
_ => self.expression().map(|expr| { StatementKind::Expression(expr.into()) } ),
|
||||
}?;
|
||||
Ok(Statement { kind, id: self.id_store.fresh() })
|
||||
@ -765,7 +767,8 @@ impl Parser {
|
||||
#[recursive_descent_method]
|
||||
fn identifier_expr(&mut self) -> ParseResult<Expression> {
|
||||
use self::ExpressionKind::*;
|
||||
let qualified_identifier = self.qualified_identifier()?;
|
||||
let components = self.qualified_identifier()?;
|
||||
let qualified_identifier = QualifiedName { id: self.id_store.fresh(), components };
|
||||
Ok(match self.token_handler.peek_kind() {
|
||||
LCurlyBrace if !self.restrictions.no_struct_literal => {
|
||||
let fields = self.record_block()?;
|
||||
@ -776,7 +779,7 @@ impl Parser {
|
||||
}
|
||||
|
||||
#[recursive_descent_method]
|
||||
fn qualified_identifier(&mut self) -> ParseResult<QualifiedName> {
|
||||
fn qualified_identifier(&mut self) -> ParseResult<Vec<Rc<String>>> {
|
||||
let mut components = vec![self.identifier()?];
|
||||
loop {
|
||||
match (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
|
||||
@ -787,7 +790,7 @@ impl Parser {
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
Ok(QualifiedName { id: self.id_store.fresh(), components })
|
||||
Ok(components)
|
||||
}
|
||||
|
||||
#[recursive_descent_method]
|
||||
@ -939,18 +942,19 @@ impl Parser {
|
||||
fn simple_pattern(&mut self) -> ParseResult<Pattern> {
|
||||
Ok(match self.token_handler.peek_kind() {
|
||||
Identifier(_) => {
|
||||
let qualified_name = self.qualified_identifier()?;
|
||||
let components = self.qualified_identifier()?;
|
||||
let qualified_identifier = QualifiedName { id: self.id_store.fresh(), components };
|
||||
match self.token_handler.peek_kind() {
|
||||
LCurlyBrace => {
|
||||
let members = delimited!(self, LCurlyBrace, record_pattern_entry, Comma, RCurlyBrace);
|
||||
Pattern::Record(qualified_name, members)
|
||||
Pattern::Record(qualified_identifier, members)
|
||||
},
|
||||
LParen => {
|
||||
let members = delimited!(self, LParen, pattern, Comma, RParen);
|
||||
Pattern::TupleStruct(qualified_name, members)
|
||||
Pattern::TupleStruct(qualified_identifier, members)
|
||||
},
|
||||
_ => {
|
||||
Pattern::VarOrName(qualified_name)
|
||||
Pattern::VarOrName(qualified_identifier)
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -1233,6 +1237,59 @@ impl Parser {
|
||||
}
|
||||
Ok(ds)
|
||||
}
|
||||
|
||||
#[recursive_descent_method]
|
||||
fn import_declaration(&mut self) -> ParseResult<ImportSpecifier> {
|
||||
expect!(self, Keyword(Import));
|
||||
let mut path_components = vec![];
|
||||
path_components.push(self.identifier()?);
|
||||
loop {
|
||||
match (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
|
||||
(Colon, Colon) => {
|
||||
self.token_handler.next(); self.token_handler.next();
|
||||
if let Identifier(_) = self.token_handler.peek_kind() {
|
||||
path_components.push(self.identifier()?);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
let imported_names = match self.token_handler.peek_kind() {
|
||||
LCurlyBrace => {
|
||||
let names = delimited!(self, LCurlyBrace, identifier, Comma, RCurlyBrace);
|
||||
ImportedNames::List(names)
|
||||
},
|
||||
Operator(ref s) if **s == "*" => {
|
||||
self.token_handler.next();
|
||||
ImportedNames::All
|
||||
},
|
||||
_ => ImportedNames::LastOfPath
|
||||
};
|
||||
|
||||
Ok(ImportSpecifier {
|
||||
id: self.id_store.fresh(),
|
||||
path_components,
|
||||
imported_names
|
||||
})
|
||||
}
|
||||
|
||||
#[recursive_descent_method]
|
||||
fn import_suffix(&mut self) -> ParseResult<ImportedNames> {
|
||||
Ok(match self.token_handler.peek_kind() {
|
||||
Operator(ref s) if **s == "*" => {
|
||||
self.token_handler.next();
|
||||
ImportedNames::All
|
||||
},
|
||||
LCurlyBrace => {
|
||||
let names = delimited!(self, LCurlyBrace, identifier, Comma, RCurlyBrace);
|
||||
ImportedNames::List(names)
|
||||
},
|
||||
_ => return ParseError::new_with_token("Expected '{{' or '*'", self.token_handler.peek()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_binary(digits: String, tok: Token) -> ParseResult<u64> {
|
||||
@ -1267,3 +1324,4 @@ fn parse_hex(digits: String, tok: Token) -> ParseResult<u64> {
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ use std::str::FromStr;
|
||||
|
||||
use super::tokenize;
|
||||
use super::ParseResult;
|
||||
use crate::ast::{ItemIdStore, AST, Expression, Statement, StatementKind, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam, PrefixOp, BinOp, QualifiedName};
|
||||
use crate::ast::{ItemIdStore, AST, Expression, Statement, StatementKind, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam, PrefixOp, BinOp, QualifiedName, ImportSpecifier, ImportedNames};
|
||||
use super::Declaration::*;
|
||||
use super::Signature;
|
||||
use super::TypeIdentifier::*;
|
||||
@ -57,6 +57,12 @@ macro_rules! decl {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! import {
|
||||
($import_spec:expr) => {
|
||||
Statement { id: ItemIdStore::new_id(), kind: StatementKind::Import($import_spec) }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! ex {
|
||||
($expr_type:expr) => { Expression::new(ItemIdStore::new_id(), $expr_type) };
|
||||
($expr_type:expr, $type_anno:expr) => { Expression::with_anno(ItemIdStore::new_id(), $expr_type, $type_anno) };
|
||||
@ -702,3 +708,55 @@ fn pattern_literals() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imports() {
|
||||
parse_test_wrap_ast! {
|
||||
"import harbinger::draughts::Norgleheim",
|
||||
import!(ImportSpecifier {
|
||||
id: ItemIdStore::new_id(),
|
||||
path_components: vec![rc!(harbinger), rc!(draughts), rc!(Norgleheim)],
|
||||
imported_names: ImportedNames::LastOfPath
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imports_2() {
|
||||
parse_test_wrap_ast! {
|
||||
"import harbinger::draughts::{Norgleheim, Xraksenlaigar}",
|
||||
import!(ImportSpecifier {
|
||||
id: ItemIdStore::new_id(),
|
||||
path_components: vec![rc!(harbinger), rc!(draughts)],
|
||||
imported_names: ImportedNames::List(vec![
|
||||
rc!(Norgleheim),
|
||||
rc!(Xraksenlaigar)
|
||||
])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imports_3() {
|
||||
parse_test_wrap_ast! {
|
||||
"import bespouri::{}",
|
||||
import!(ImportSpecifier {
|
||||
id: ItemIdStore::new_id(),
|
||||
path_components: vec![rc!(bespouri)],
|
||||
imported_names: ImportedNames::List(vec![])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn imports_4() {
|
||||
parse_test_wrap_ast! {
|
||||
"import bespouri::*",
|
||||
import!(ImportSpecifier {
|
||||
id: ItemIdStore::new_id(),
|
||||
path_components: vec![rc!(bespouri)],
|
||||
imported_names: ImportedNames::All
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ impl<'a> Reducer<'a> {
|
||||
match &stmt.kind {
|
||||
StatementKind::Expression(expr) => Stmt::Expr(self.expression(&expr)),
|
||||
StatementKind::Declaration(decl) => self.declaration(&decl),
|
||||
StatementKind::Import(_) => Stmt::Noop,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ impl<'a> ScopeResolver<'a> {
|
||||
match statement.kind {
|
||||
StatementKind::Declaration(ref decl) => self.decl(decl),
|
||||
StatementKind::Expression(ref expr) => self.expr(expr),
|
||||
StatementKind::Import(_) => Ok(())
|
||||
}?;
|
||||
}
|
||||
Ok(())
|
||||
@ -32,6 +33,7 @@ impl<'a> ScopeResolver<'a> {
|
||||
match statement.kind {
|
||||
StatementKind::Declaration(ref decl) => self.decl(decl),
|
||||
StatementKind::Expression(ref expr) => self.expr(expr),
|
||||
StatementKind::Import(_) => Ok(())
|
||||
}?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -274,6 +274,7 @@ impl<'a> TypeContext<'a> {
|
||||
match &statement.kind {
|
||||
StatementKind::Expression(e) => self.expr(e),
|
||||
StatementKind::Declaration(decl) => self.decl(&decl),
|
||||
StatementKind::Import(_) => Ok(ty!(Unit)),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user