Skip to content

Commit

Permalink
Parse import statements as per issue #27
Browse files Browse the repository at this point in the history
  • Loading branch information
KCreate committed Apr 3, 2022
1 parent 3e64f33 commit 4c4dbe0
Show file tree
Hide file tree
Showing 12 changed files with 302 additions and 99 deletions.
16 changes: 2 additions & 14 deletions examples/test.ch
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,5 @@
* SOFTWARE.
*/

const data = (1, 2, 3, 4, 5)

const result = data.map(->(e, i) e + i)

print(data, result)









import bar as baz + 1
print(bar)
32 changes: 32 additions & 0 deletions src/charly/core/compiler/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class Node : std::enable_shared_from_this<Node> {
Unknown = 0,

// Statements
StatementList,
Block,
Return,
Break,
Expand Down Expand Up @@ -267,6 +268,33 @@ class Statement : public Node {
// 1 + x, false, foo(bar)
class Expression : public Statement {};

class StatementList : public Statement {
AST_NODE(StatementList)
public:
template <typename... Args>
explicit StatementList(Args&&... params) : statements({ std::forward<Args>(params)... }) {
if (!statements.empty()) {
this->set_begin(this->statements.front()->location());
this->set_end(this->statements.back()->location());
}
}
virtual ~StatementList() = default;

std::vector<ref<Statement>> statements;

void append_statement(const ref<Statement>& stmt) {
if (statements.empty()) {
set_begin(stmt);
}
statements.push_back(stmt);
set_end(stmt);
}

CHILDREN() {
CHILD_VECTOR(statements)
}
};

// {
// ...
// }
Expand Down Expand Up @@ -603,6 +631,10 @@ class String final : public ConstantAtom<std::string> {
public:
using ConstantAtom<std::string>::ConstantAtom;

explicit String(const ref<Id>& id) : ConstantAtom<std::string>(id->value) {
set_location(id);
}

void dump_info(std::ostream& out) const override;

bool truthyness() const override {
Expand Down
175 changes: 151 additions & 24 deletions src/charly/core/compiler/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,14 @@ void Parser::parse_block_body(const ref<Block>& block) {
block->set_begin(stmt);
}

block->statements.push_back(stmt);
if (auto stmt_list = cast<StatementList>(stmt)) {
for (auto entry : stmt_list->statements) {
block->statements.push_back(entry);
}
} else {
block->statements.push_back(stmt);
}

block->set_end(stmt);

parsed_statements++;
Expand Down Expand Up @@ -171,6 +178,12 @@ ref<Statement> Parser::parse_statement() {
stmt = parse_declaration();
break;
}
case TokenType::Export: {
return parse_export();
}
case TokenType::Import: {
return parse_import();
}
default: {
stmt = parse_jump_statement();
break;
Expand Down Expand Up @@ -200,17 +213,6 @@ ref<Statement> Parser::parse_statement() {

break;
}
case Node::Type::Import: {
ref<Import> import = cast<Import>(stmt);

if (ref<Name> name = cast<Name>(import->source)) {
ref<Declaration> declaration = make<Declaration>(name, import, true);
declaration->set_location(import);
stmt = declaration;
}

break;
}
default: {
break;
}
Expand All @@ -230,9 +232,6 @@ ref<Statement> Parser::parse_jump_statement() {
case TokenType::Continue: {
return parse_continue();
}
case TokenType::Export: {
return parse_export();
}
default: {
return parse_throw_statement();
}
Expand Down Expand Up @@ -607,7 +606,7 @@ ref<Expression> Parser::parse_expression() {
return parse_yield();
}
case TokenType::Import: {
return parse_import();
return parse_import_expression();
}
default: {
return parse_assignment();
Expand All @@ -627,19 +626,147 @@ ref<Yield> Parser::parse_yield() {
return node;
}

ref<Import> Parser::parse_import() {
ref<Statement> Parser::parse_import() {
Location begin = m_token.location;
eat(TokenType::Import);
ref<Expression> source = parse_expression();

if (ref<Id> id = cast<Id>(source)) {
source = make<Name>(id);
}
if (skip(TokenType::LeftCurly)) {
// unpack import statement
// import { foo [as f] } from libfoo [as foolib]
std::vector<std::tuple<ref<Name>, ref<Name>>> unpack_elements;
do {
auto field = make<Name>(parse_identifier_token());
ref<Name> field_name;

ref<Import> node = make<Import>(source);
node->set_begin(begin);
if (skip(TokenType::As)) {
field_name = make<Name>(parse_identifier_token());
}

return node;
unpack_elements.emplace_back(field, field_name);
} while (skip(TokenType::Comma));

eat(TokenType::RightCurly);
eat(TokenType::From);

ref<Expression> source;
ref<Name> name;
if (skip(TokenType::LeftParen)) {
source = parse_expression();
eat(TokenType::RightParen);
} else {
source = parse_expression();
if (auto id = cast<Id>(source)) {
source = make<String>(id);
name = make<Name>(id);
}
}

ref<Name> renamed_name;
if (skip(TokenType::As)) {
renamed_name = make<Name>(parse_identifier_token());
}

// generate unpack assignments
CHECK(unpack_elements.size());
auto unpack_dict = make<Dict>();
for (const auto& entry : unpack_elements) {
ref<Name> field = std::get<0>(entry);
unpack_dict->elements.push_back(make<DictEntry>(field));
}

auto unpack_target = create_unpack_target(unpack_dict, true);

auto import = make<Import>(source);
import->set_begin(begin);

ref<StatementList> statements;
if (name && renamed_name) {
// import {...} from foo as bar
statements = make<StatementList>(
make<Declaration>(name, import, true, false),
make<Declaration>(renamed_name, make<Id>(name), true, false),
make<UnpackDeclaration>(unpack_target, make<Id>(name), true)
);
} else if (name) {
// import {...} from foo
statements = make<StatementList>(
make<Declaration>(name, import, true, false),
make<UnpackDeclaration>(unpack_target, make<Id>(name), true)
);
} else if (renamed_name) {
// import {...} from "foo" as bar
statements = make<StatementList>(
make<Declaration>(renamed_name, import, true, false),
make<UnpackDeclaration>(unpack_target, make<Id>(renamed_name), true)
);
} else {
// import {...} from "foo"
statements = make<StatementList>(
make<UnpackDeclaration>(unpack_target, import, true)
);
}

// emit renamed unpack arguments
for (auto& entry : unpack_elements) {
ref<Name> field = std::get<0>(entry);
ref<Name> field_name = std::get<1>(entry);

if (field_name) {
auto rename_decl = make<Declaration>(field_name, make<Id>(field), true, false);
statements->append_statement(rename_decl);
}
}

return statements;
} else {
// regular import statement
// import foo
// import "foo"
// import foo as bar
// import "foo" as bar
ref<Expression> source;
ref<Name> name;
if (skip(TokenType::LeftParen)) {
source = parse_expression();
eat(TokenType::RightParen);
} else {
source = parse_expression();
if (auto id = cast<Id>(source)) {
source = make<String>(id);
name = make<Name>(id);
}
}

ref<Name> renamed_name;
if (skip(TokenType::As)) {
renamed_name = make<Name>(parse_identifier_token());
}

auto import = make<Import>(source);
import->set_begin(begin);

if (name && renamed_name) {
return make<StatementList>(
make<Declaration>(name, import, true, false),
make<Declaration>(renamed_name, make<Id>(name), true, false)
);
} else if (name) {
return make<Declaration>(name, import, true, false);
} else if (renamed_name) {
return make<Declaration>(renamed_name, import, true, false);
} else {
return import;
}
}
}

ref<Expression> Parser::parse_import_expression() {
Location begin = m_token.location;
eat(TokenType::Import);
auto source = parse_expression();
auto import = make<Import>(source);
import->set_begin(begin);
return import;
}

ref<Expression> Parser::parse_assignment() {
Expand Down
3 changes: 2 additions & 1 deletion src/charly/core/compiler/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ class Parser : public Lexer {
ref<Continue> parse_continue();
ref<TryFinally> parse_defer();
ref<Throw> parse_throw();
ref<Statement> parse_import();
ref<Expression> parse_import_expression();
ref<Export> parse_export();

// control statements
Expand All @@ -153,7 +155,6 @@ class Parser : public Lexer {
void parse_call_arguments(std::vector<ref<Expression>>& result);
ref<Expression> parse_expression();
ref<Yield> parse_yield();
ref<Import> parse_import();
ref<Expression> parse_assignment();
ref<Expression> parse_ternary();
ref<Expression> parse_binaryop();
Expand Down
4 changes: 1 addition & 3 deletions src/charly/core/compiler/passes/desugar_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ ref<Statement> DesugarPass::transform(const ref<Block>& node) {
void DesugarPass::inspect_leave(const ref<Import>& node) {
ref<Expression> source = node->source;

if (ref<Name> name = cast<Name>(source)) {
source = make<String>(name->value);
} else {
if (!isa<String>(source)) {
source = make<BuiltinOperation>(ir::BuiltinId::caststring, source);
}

Expand Down
27 changes: 15 additions & 12 deletions src/charly/core/compiler/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@

namespace charly::core::compiler {

enum class TokenType {
enum class TokenType
{
Eof,

// literals
Expand Down Expand Up @@ -70,6 +71,7 @@ enum class TokenType {
Final,
Finally,
For,
From,
Func,
Guard,
If,
Expand Down Expand Up @@ -148,17 +150,17 @@ enum class TokenType {

// string representations of token types
static std::string kTokenTypeStrings[] = {
"EOF", "integer", "float", "true", "false", "identifier", "character", "string", "formatstring",
"null", "self", "super", "as", "await", "break", "__builtin", "case", "catch",
"class", "const", "continue", "default", "defer", "do", "else", "export", "extends",
"final", "finally", "for", "func", "guard", "if", "import", "in", "let",
"loop", "match", "private", "property", "return", "spawn", "static", "switch", "throw",
"try", "typeof", "unless", "until", "while", "yield", "=", "+", "-",
"*", "/", "%", "**", "==", "!=", "<", ">", "<=",
">=", "&&", "||", "|", "^", "&", "<<", ">>", ">>>",
"!", "~", "(", ")", "{", "}", "[", "]", ".",
"..", "...", ":", ",", ";", "@", "<-", "->", "=>",
"?", "comment", "newline", "whitespace"
"EOF", "integer", "float", "true", "false", "identifier", "character", "string", "formatstring",
"null", "self", "super", "as", "await", "break", "__builtin", "case", "catch",
"class", "const", "continue", "default", "defer", "do", "else", "export", "extends",
"final", "finally", "for", "from", "func", "guard", "if", "import", "in",
"let", "loop", "match", "private", "property", "return", "spawn", "static", "switch",
"throw", "try", "typeof", "unless", "until", "while", "yield", "=", "+",
"-", "*", "/", "%", "**", "==", "!=", "<", ">",
"<=", ">=", "&&", "||", "|", "^", "&", "<<", ">>",
">>>", "!", "~", "(", ")", "{", "}", "[", "]",
".", "..", "...", ":", ",", ";", "@", "<-", "->",
"=>", "?", "comment", "newline", "whitespace"
};

// identifiers with these names get remapped to keyword tokens
Expand Down Expand Up @@ -189,6 +191,7 @@ static const std::unordered_map<std::string, TokenType> kKeywordsAndLiterals = {
{ "final", TokenType::Final },
{ "finally", TokenType::Finally },
{ "for", TokenType::For },
{ "from", TokenType::From },
{ "func", TokenType::Func },
{ "guard", TokenType::Guard },
{ "if", TokenType::If },
Expand Down
Loading

0 comments on commit 4c4dbe0

Please sign in to comment.