Import statement syntax

This commit is contained in:
greg 2019-09-21 02:30:28 -07:00
parent 603ea89b98
commit a054de56a2
6 changed files with 148 additions and 10 deletions

View File

@ -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>>)
}

View File

@ -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)
}

View File

@ -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
})
}
}

View File

@ -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,
}
}

View File

@ -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(())

View File

@ -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)),
}
}