implement from-import statement
This commit is contained in:
parent
deddf1d77e
commit
899a973315
|
@ -38,6 +38,8 @@ pub enum KeywordKind {
|
||||||
Run,
|
Run,
|
||||||
Lua,
|
Lua,
|
||||||
Namespace,
|
Namespace,
|
||||||
|
From,
|
||||||
|
Import,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for KeywordKind {
|
impl ToString for KeywordKind {
|
||||||
|
@ -96,6 +98,8 @@ impl KeywordKind {
|
||||||
Self::Run => "run",
|
Self::Run => "run",
|
||||||
Self::Lua => "lua",
|
Self::Lua => "lua",
|
||||||
Self::Namespace => "namespace",
|
Self::Namespace => "namespace",
|
||||||
|
Self::From => "from",
|
||||||
|
Self::Import => "import",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use getset::Getters;
|
||||||
use crate::{
|
use crate::{
|
||||||
base::{
|
base::{
|
||||||
source_file::{SourceElement, Span},
|
source_file::{SourceElement, Span},
|
||||||
Handler,
|
DummyHandler, Handler,
|
||||||
},
|
},
|
||||||
lexical::{
|
lexical::{
|
||||||
token::{Identifier, Keyword, KeywordKind, Punctuation, StringLiteral, Token},
|
token::{Identifier, Keyword, KeywordKind, Punctuation, StringLiteral, Token},
|
||||||
|
@ -32,12 +32,14 @@ use super::{statement::Block, ConnectedList};
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub enum Declaration {
|
pub enum Declaration {
|
||||||
Function(Function),
|
Function(Function),
|
||||||
|
Import(Import),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceElement for Declaration {
|
impl SourceElement for Declaration {
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Self::Function(function) => function.span(),
|
Self::Function(function) => function.span(),
|
||||||
|
Self::Import(import) => import.span(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,6 +172,58 @@ impl SourceElement for Function {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Syntax Synopsis:
|
||||||
|
///
|
||||||
|
/// ``` ebnf
|
||||||
|
/// Import:
|
||||||
|
/// 'from' StringLiteral 'import' ('*' | Identifier (',' Identifier)*) ';'
|
||||||
|
/// ;
|
||||||
|
/// ```
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
pub struct Import {
|
||||||
|
#[get = "pub"]
|
||||||
|
from_keyword: Keyword,
|
||||||
|
#[get = "pub"]
|
||||||
|
module: StringLiteral,
|
||||||
|
#[get = "pub"]
|
||||||
|
import_keyword: Keyword,
|
||||||
|
#[get = "pub"]
|
||||||
|
items: ImportItems,
|
||||||
|
#[get = "pub"]
|
||||||
|
semicolon: Punctuation,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub enum ImportItems {
|
||||||
|
All(Punctuation),
|
||||||
|
Named(ConnectedList<Identifier, Punctuation>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Import {
|
||||||
|
/// Dissolves the [`Import`] into its components.
|
||||||
|
#[must_use]
|
||||||
|
pub fn dissolve(self) -> (Keyword, StringLiteral, Keyword, ImportItems, Punctuation) {
|
||||||
|
(
|
||||||
|
self.from_keyword,
|
||||||
|
self.module,
|
||||||
|
self.import_keyword,
|
||||||
|
self.items,
|
||||||
|
self.semicolon,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceElement for Import {
|
||||||
|
fn span(&self) -> Span {
|
||||||
|
self.from_keyword
|
||||||
|
.span()
|
||||||
|
.join(&self.semicolon.span())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
pub fn parse_annotation(&mut self, handler: &impl Handler<Error>) -> Option<Annotation> {
|
pub fn parse_annotation(&mut self, handler: &impl Handler<Error>) -> Option<Annotation> {
|
||||||
match self.stop_at_significant() {
|
match self.stop_at_significant() {
|
||||||
|
@ -229,31 +283,9 @@ impl<'a> Parser<'a> {
|
||||||
Reading::Atomic(Token::Keyword(function_keyword))
|
Reading::Atomic(Token::Keyword(function_keyword))
|
||||||
if function_keyword.keyword == KeywordKind::Function =>
|
if function_keyword.keyword == KeywordKind::Function =>
|
||||||
{
|
{
|
||||||
// eat the function keyword
|
let function = self.parse_function(handler)?;
|
||||||
self.forward();
|
|
||||||
|
|
||||||
// parse the identifier
|
Some(Declaration::Function(function))
|
||||||
let identifier = self.parse_identifier(handler)?;
|
|
||||||
let delimited_tree = self.parse_enclosed_list(
|
|
||||||
Delimiter::Parenthesis,
|
|
||||||
',',
|
|
||||||
|parser: &mut Parser<'_>| parser.parse_identifier(handler),
|
|
||||||
handler,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// parse the block
|
|
||||||
let block = self.parse_block(handler)?;
|
|
||||||
|
|
||||||
Some(Declaration::Function(Function {
|
|
||||||
public_keyword: None,
|
|
||||||
annotations: Vec::new(),
|
|
||||||
function_keyword,
|
|
||||||
identifier,
|
|
||||||
open_paren: delimited_tree.open,
|
|
||||||
parameters: delimited_tree.list,
|
|
||||||
close_paren: delimited_tree.close,
|
|
||||||
block,
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Reading::Atomic(Token::Keyword(pub_keyword))
|
Reading::Atomic(Token::Keyword(pub_keyword))
|
||||||
|
@ -263,47 +295,13 @@ impl<'a> Parser<'a> {
|
||||||
self.forward();
|
self.forward();
|
||||||
|
|
||||||
// parse the function keyword
|
// parse the function keyword
|
||||||
let function_keyword_reading = self.next_significant_token();
|
let function = self.parse_function(handler)?;
|
||||||
|
|
||||||
match function_keyword_reading {
|
|
||||||
Reading::Atomic(Token::Keyword(function_keyword))
|
|
||||||
if function_keyword.keyword == KeywordKind::Function =>
|
|
||||||
{
|
|
||||||
// eat the function keyword
|
|
||||||
self.forward();
|
|
||||||
|
|
||||||
// parse the identifier
|
|
||||||
let identifier = self.parse_identifier(handler)?;
|
|
||||||
let delimited_tree = self.parse_enclosed_list(
|
|
||||||
Delimiter::Parenthesis,
|
|
||||||
',',
|
|
||||||
|parser: &mut Parser<'_>| parser.parse_identifier(handler),
|
|
||||||
handler,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// parse the block
|
|
||||||
let block = self.parse_block(handler)?;
|
|
||||||
|
|
||||||
Some(Declaration::Function(Function {
|
Some(Declaration::Function(Function {
|
||||||
public_keyword: Some(pub_keyword),
|
public_keyword: Some(pub_keyword),
|
||||||
annotations: Vec::new(),
|
..function
|
||||||
function_keyword,
|
|
||||||
identifier,
|
|
||||||
open_paren: delimited_tree.open,
|
|
||||||
parameters: delimited_tree.list,
|
|
||||||
close_paren: delimited_tree.close,
|
|
||||||
block,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
unexpected => {
|
|
||||||
handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
|
|
||||||
expected: SyntaxKind::Keyword(KeywordKind::Function),
|
|
||||||
found: unexpected.into_token(),
|
|
||||||
}));
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse annotations
|
// parse annotations
|
||||||
Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => {
|
Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => {
|
||||||
|
@ -316,16 +314,70 @@ impl<'a> Parser<'a> {
|
||||||
annotations.push(annotation);
|
annotations.push(annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the function
|
self.parse_declaration(handler).and_then(|declaration| {
|
||||||
self.parse_declaration(handler)
|
if let Declaration::Function(mut function) = declaration {
|
||||||
.map(|declaration| match declaration {
|
|
||||||
Declaration::Function(mut function) => {
|
|
||||||
function.annotations.extend(annotations);
|
function.annotations.extend(annotations);
|
||||||
Declaration::Function(function)
|
Some(Declaration::Function(function))
|
||||||
|
} else {
|
||||||
|
handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
|
||||||
|
expected: SyntaxKind::Keyword(KeywordKind::Function),
|
||||||
|
found: None,
|
||||||
|
}));
|
||||||
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reading::Atomic(Token::Keyword(from_keyword))
|
||||||
|
if from_keyword.keyword == KeywordKind::From =>
|
||||||
|
{
|
||||||
|
// eat the from keyword
|
||||||
|
self.forward();
|
||||||
|
|
||||||
|
// parse the module
|
||||||
|
let module = self.parse_string_literal(handler)?;
|
||||||
|
|
||||||
|
let import_keyword = self.parse_keyword(KeywordKind::Import, handler)?;
|
||||||
|
|
||||||
|
// TODO: re-enable when the asterisk is supported
|
||||||
|
let items = // match self.stop_at_significant() {
|
||||||
|
// Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == '*' => {
|
||||||
|
// eat the asterisk
|
||||||
|
// self.forward();
|
||||||
|
|
||||||
|
// ImportItems::All(punc)
|
||||||
|
// }
|
||||||
|
// _ =>
|
||||||
|
self.try_parse(|parser| parser
|
||||||
|
.parse_connected_list(
|
||||||
|
',',
|
||||||
|
|parser| parser.parse_identifier(&DummyHandler),
|
||||||
|
handler,
|
||||||
|
)
|
||||||
|
.map(ImportItems::Named)) // ,
|
||||||
|
// }
|
||||||
|
;
|
||||||
|
|
||||||
|
if let Some(items) = items {
|
||||||
|
let semicolon = self.parse_punctuation(';', true, handler)?;
|
||||||
|
|
||||||
|
Some(Declaration::Import(Import {
|
||||||
|
from_keyword,
|
||||||
|
module,
|
||||||
|
import_keyword,
|
||||||
|
items,
|
||||||
|
semicolon,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
|
||||||
|
expected: SyntaxKind::Identifier,
|
||||||
|
found: self.stop_at_significant().into_token(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unexpected => {
|
unexpected => {
|
||||||
// make progress
|
// make progress
|
||||||
self.forward();
|
self.forward();
|
||||||
|
@ -339,4 +391,40 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_function(&mut self, handler: &impl Handler<Error>) -> Option<Function> {
|
||||||
|
if let Reading::Atomic(Token::Keyword(function_keyword)) = self.stop_at_significant() {
|
||||||
|
// eat the function keyword
|
||||||
|
self.forward();
|
||||||
|
|
||||||
|
// parse the identifier
|
||||||
|
let identifier = self.parse_identifier(handler)?;
|
||||||
|
let delimited_tree = self.parse_enclosed_list(
|
||||||
|
Delimiter::Parenthesis,
|
||||||
|
',',
|
||||||
|
|parser: &mut Parser<'_>| parser.parse_identifier(handler),
|
||||||
|
handler,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// parse the block
|
||||||
|
let block = self.parse_block(handler)?;
|
||||||
|
|
||||||
|
Some(Function {
|
||||||
|
public_keyword: None,
|
||||||
|
annotations: Vec::new(),
|
||||||
|
function_keyword,
|
||||||
|
identifier,
|
||||||
|
open_paren: delimited_tree.open,
|
||||||
|
parameters: delimited_tree.list,
|
||||||
|
close_paren: delimited_tree.close,
|
||||||
|
block,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
|
||||||
|
expected: SyntaxKind::Keyword(KeywordKind::Function),
|
||||||
|
found: self.peek().into_token(),
|
||||||
|
}));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use getset::Getters;
|
||||||
use crate::{
|
use crate::{
|
||||||
base::{
|
base::{
|
||||||
source_file::{SourceElement, Span},
|
source_file::{SourceElement, Span},
|
||||||
Handler,
|
DummyHandler, Handler,
|
||||||
},
|
},
|
||||||
lexical::{
|
lexical::{
|
||||||
token::{Punctuation, Token},
|
token::{Punctuation, Token},
|
||||||
|
@ -149,6 +149,45 @@ impl<'a> Parser<'a> {
|
||||||
close: delimited_tree.close,
|
close: delimited_tree.close,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a list of elements separated by a separator.
|
||||||
|
///
|
||||||
|
/// The parser position must be at the connected list of the first element. It will
|
||||||
|
/// consume the whole connected list and move the next token after the list.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// - if the parser position is not at the connected list of the given element.
|
||||||
|
/// - any error returned by the given parser function.
|
||||||
|
pub fn parse_connected_list<T>(
|
||||||
|
&mut self,
|
||||||
|
seperator: char,
|
||||||
|
mut f: impl FnMut(&mut Self) -> Option<T>,
|
||||||
|
_handler: &impl Handler<Error>,
|
||||||
|
) -> Option<ConnectedList<T, Punctuation>> {
|
||||||
|
let first = f(self)?;
|
||||||
|
|
||||||
|
let mut rest = Vec::new();
|
||||||
|
|
||||||
|
while let Some(sep) =
|
||||||
|
self.try_parse(|parser| parser.parse_punctuation(seperator, true, &DummyHandler))
|
||||||
|
{
|
||||||
|
if let Some(element) = self.try_parse(&mut f) {
|
||||||
|
rest.push((sep, element));
|
||||||
|
} else {
|
||||||
|
return Some(ConnectedList {
|
||||||
|
first,
|
||||||
|
rest,
|
||||||
|
trailing_separator: Some(sep),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(ConnectedList {
|
||||||
|
first,
|
||||||
|
rest,
|
||||||
|
trailing_separator: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Element: SourceElement, Separator: SourceElement> SourceElement
|
impl<Element: SourceElement, Separator: SourceElement> SourceElement
|
||||||
|
|
|
@ -8,3 +8,5 @@ pub mod error;
|
||||||
pub mod lua;
|
pub mod lua;
|
||||||
#[cfg(feature = "shulkerbox")]
|
#[cfg(feature = "shulkerbox")]
|
||||||
pub mod transpiler;
|
pub mod transpiler;
|
||||||
|
|
||||||
|
mod util;
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
//! Transpiler for `ShulkerScript`
|
//! Transpiler for `ShulkerScript`
|
||||||
|
|
||||||
use chksum_md5 as md5;
|
use chksum_md5 as md5;
|
||||||
use std::{collections::HashMap, sync::RwLock};
|
use std::{collections::HashMap, iter, sync::RwLock};
|
||||||
|
|
||||||
use shulkerbox::datapack::{self, Command, Datapack, Execute};
|
use shulkerbox::datapack::{self, Command, Datapack, Execute};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
base::{source_file::SourceElement, Handler},
|
base::{source_file::SourceElement, Handler},
|
||||||
syntax::syntax_tree::{
|
syntax::syntax_tree::{
|
||||||
declaration::Declaration,
|
declaration::{Declaration, ImportItems},
|
||||||
expression::{Expression, FunctionCall, Primary},
|
expression::{Expression, FunctionCall, Primary},
|
||||||
program::{Namespace, ProgramFile},
|
program::{Namespace, ProgramFile},
|
||||||
statement::{
|
statement::{
|
||||||
|
@ -26,13 +26,15 @@ pub struct Transpiler {
|
||||||
datapack: shulkerbox::datapack::Datapack,
|
datapack: shulkerbox::datapack::Datapack,
|
||||||
/// Key: (program identifier, function name)
|
/// Key: (program identifier, function name)
|
||||||
functions: RwLock<HashMap<(String, String), FunctionData>>,
|
functions: RwLock<HashMap<(String, String), FunctionData>>,
|
||||||
function_locations: RwLock<HashMap<(String, String), String>>,
|
function_locations: RwLock<HashMap<(String, String), (String, bool)>>,
|
||||||
|
aliases: RwLock<HashMap<(String, String), (String, String)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct FunctionData {
|
struct FunctionData {
|
||||||
namespace: String,
|
namespace: String,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
|
public: bool,
|
||||||
annotations: HashMap<String, Option<String>>,
|
annotations: HashMap<String, Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +46,7 @@ impl Transpiler {
|
||||||
datapack: shulkerbox::datapack::Datapack::new(pack_format),
|
datapack: shulkerbox::datapack::Datapack::new(pack_format),
|
||||||
functions: RwLock::new(HashMap::new()),
|
functions: RwLock::new(HashMap::new()),
|
||||||
function_locations: RwLock::new(HashMap::new()),
|
function_locations: RwLock::new(HashMap::new()),
|
||||||
|
aliases: RwLock::new(HashMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,23 +69,7 @@ impl Transpiler {
|
||||||
Ident: AsRef<str>,
|
Ident: AsRef<str>,
|
||||||
{
|
{
|
||||||
for (identifier, program) in programs {
|
for (identifier, program) in programs {
|
||||||
self.transpile_program(program, identifier.as_ref(), handler)?;
|
self.transpile_program_declarations(program, identifier.as_ref(), handler);
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transpiles the given program.
|
|
||||||
fn transpile_program(
|
|
||||||
&mut self,
|
|
||||||
program: &ProgramFile,
|
|
||||||
identifier: &str,
|
|
||||||
handler: &impl Handler<TranspileError>,
|
|
||||||
) -> TranspileResult<()> {
|
|
||||||
let namespace = program.namespace();
|
|
||||||
|
|
||||||
for declaration in program.declarations() {
|
|
||||||
self.transpile_declaration(declaration, namespace, identifier, handler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut always_transpile_functions = Vec::new();
|
let mut always_transpile_functions = Vec::new();
|
||||||
|
@ -107,6 +94,20 @@ impl Transpiler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transpiles the given program.
|
||||||
|
fn transpile_program_declarations(
|
||||||
|
&mut self,
|
||||||
|
program: &ProgramFile,
|
||||||
|
identifier: &str,
|
||||||
|
handler: &impl Handler<TranspileError>,
|
||||||
|
) {
|
||||||
|
let namespace = program.namespace();
|
||||||
|
|
||||||
|
for declaration in program.declarations() {
|
||||||
|
self.transpile_declaration(declaration, namespace, identifier, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Transpiles the given declaration.
|
/// Transpiles the given declaration.
|
||||||
fn transpile_declaration(
|
fn transpile_declaration(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -136,10 +137,34 @@ impl Transpiler {
|
||||||
FunctionData {
|
FunctionData {
|
||||||
namespace: namespace.namespace_name().str_content().to_string(),
|
namespace: namespace.namespace_name().str_content().to_string(),
|
||||||
statements,
|
statements,
|
||||||
|
public: function.is_public(),
|
||||||
annotations,
|
annotations,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Declaration::Import(import) => {
|
||||||
|
let path = import.module().str_content();
|
||||||
|
let import_identifier =
|
||||||
|
super::util::calculate_import_identifier(program_identifier, path);
|
||||||
|
|
||||||
|
let mut aliases = self.aliases.write().unwrap();
|
||||||
|
|
||||||
|
match import.items() {
|
||||||
|
ImportItems::All(_) => todo!("Importing all items is not yet supported."),
|
||||||
|
ImportItems::Named(list) => {
|
||||||
|
let items = iter::once(list.first())
|
||||||
|
.chain(list.rest().iter().map(|(_, ident)| ident));
|
||||||
|
|
||||||
|
for item in items {
|
||||||
|
let name = item.span.str();
|
||||||
|
aliases.insert(
|
||||||
|
(program_identifier.to_string(), name.to_string()),
|
||||||
|
(import_identifier.clone(), name.to_string()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,14 +178,32 @@ impl Transpiler {
|
||||||
handler: &impl Handler<TranspileError>,
|
handler: &impl Handler<TranspileError>,
|
||||||
) -> TranspileResult<String> {
|
) -> TranspileResult<String> {
|
||||||
let program_query = (program_identifier.to_string(), name.to_string());
|
let program_query = (program_identifier.to_string(), name.to_string());
|
||||||
|
let alias_query = {
|
||||||
|
let aliases = self.aliases.read().unwrap();
|
||||||
|
aliases.get(&program_query).cloned()
|
||||||
|
};
|
||||||
let already_transpiled = {
|
let already_transpiled = {
|
||||||
let locations = self.function_locations.read().unwrap();
|
let locations = self.function_locations.read().unwrap();
|
||||||
locations.get(&program_query).is_some()
|
locations
|
||||||
|
.get(&program_query)
|
||||||
|
.or_else(|| {
|
||||||
|
alias_query
|
||||||
|
.clone()
|
||||||
|
.and_then(|q| locations.get(&q).filter(|(_, p)| *p))
|
||||||
|
})
|
||||||
|
.is_some()
|
||||||
};
|
};
|
||||||
if !already_transpiled {
|
if !already_transpiled {
|
||||||
let statements = {
|
let statements = {
|
||||||
let functions = self.functions.read().unwrap();
|
let functions = self.functions.read().unwrap();
|
||||||
let function_data = functions.get(&program_query).ok_or_else(|| {
|
let function_data = functions
|
||||||
|
.get(&program_query)
|
||||||
|
.or_else(|| {
|
||||||
|
alias_query
|
||||||
|
.clone()
|
||||||
|
.and_then(|q| functions.get(&q).filter(|f| f.public))
|
||||||
|
})
|
||||||
|
.ok_or_else(|| {
|
||||||
let error = TranspileError::MissingFunctionDeclaration(name.to_string());
|
let error = TranspileError::MissingFunctionDeclaration(name.to_string());
|
||||||
handler.receive(error.clone());
|
handler.receive(error.clone());
|
||||||
error
|
error
|
||||||
|
@ -170,7 +213,14 @@ impl Transpiler {
|
||||||
let commands = self.transpile_function(&statements, program_identifier, handler)?;
|
let commands = self.transpile_function(&statements, program_identifier, handler)?;
|
||||||
|
|
||||||
let functions = self.functions.read().unwrap();
|
let functions = self.functions.read().unwrap();
|
||||||
let function_data = functions.get(&program_query).ok_or_else(|| {
|
let function_data = functions
|
||||||
|
.get(&program_query)
|
||||||
|
.or_else(|| {
|
||||||
|
alias_query
|
||||||
|
.clone()
|
||||||
|
.and_then(|q| functions.get(&q).filter(|f| f.public))
|
||||||
|
})
|
||||||
|
.ok_or_else(|| {
|
||||||
let error = TranspileError::MissingFunctionDeclaration(name.to_string());
|
let error = TranspileError::MissingFunctionDeclaration(name.to_string());
|
||||||
handler.receive(error.clone());
|
handler.receive(error.clone());
|
||||||
error
|
error
|
||||||
|
@ -208,19 +258,20 @@ impl Transpiler {
|
||||||
|
|
||||||
self.function_locations.write().unwrap().insert(
|
self.function_locations.write().unwrap().insert(
|
||||||
(program_identifier.to_string(), name.to_string()),
|
(program_identifier.to_string(), name.to_string()),
|
||||||
function_location,
|
(function_location, function_data.public),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let locations = self.function_locations.read().unwrap();
|
let locations = self.function_locations.read().unwrap();
|
||||||
locations
|
locations
|
||||||
.get(&program_query)
|
.get(&program_query)
|
||||||
|
.or_else(|| alias_query.and_then(|q| locations.get(&q).filter(|(_, p)| *p)))
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
let error = TranspileError::MissingFunctionDeclaration(name.to_string());
|
let error = TranspileError::MissingFunctionDeclaration(name.to_string());
|
||||||
handler.receive(error.clone());
|
handler.receive(error.clone());
|
||||||
error
|
error
|
||||||
})
|
})
|
||||||
.map(String::to_owned)
|
.map(|(s, _)| s.to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transpile_function(
|
fn transpile_function(
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
fn normalize_program_identifier<S>(identifier: S) -> String
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
identifier
|
||||||
|
.as_ref()
|
||||||
|
.split('/')
|
||||||
|
.fold(Vec::new(), |mut acc, el| match el {
|
||||||
|
"." | "" => acc,
|
||||||
|
".." => {
|
||||||
|
acc.pop();
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
acc.push(el);
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.join("/")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculate_import_identifier<S, T>(current_identifier: S, import_path: T) -> String
|
||||||
|
where
|
||||||
|
S: AsRef<str>,
|
||||||
|
T: AsRef<str>,
|
||||||
|
{
|
||||||
|
if import_path.as_ref().starts_with('/') {
|
||||||
|
normalize_program_identifier(&import_path.as_ref()[1..])
|
||||||
|
} else {
|
||||||
|
let mut identifier_elements = current_identifier.as_ref().split('/').collect::<Vec<_>>();
|
||||||
|
identifier_elements.pop();
|
||||||
|
normalize_program_identifier(identifier_elements.join("/") + "/" + import_path.as_ref())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue