Skip to content

Commit

Permalink
🥐 Introduce Boxing
Browse files Browse the repository at this point in the history
- Introduce Boxing
- Convert Real-Time Engine to C++
  • Loading branch information
Theo Weidmann committed Feb 5, 2017
1 parent f74fc4a commit 927d4d5
Show file tree
Hide file tree
Showing 116 changed files with 6,205 additions and 5,770 deletions.
188 changes: 115 additions & 73 deletions Emojicode.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

99 changes: 51 additions & 48 deletions EmojicodeCompiler/AbstractParser.cpp
Expand Up @@ -6,16 +6,18 @@
// Copyright © 2016 Theo Weidmann. All rights reserved.
//

#include <map>
#include <vector>
#include "AbstractParser.hpp"
#include "Function.hpp"
#include "Protocol.hpp"
#include "TypeContext.hpp"

ParsedTypeName AbstractParser::parseTypeName() {
if (stream_.nextTokenIs(TokenType::Variable)) {
throw CompilerErrorException(stream_.consumeToken(TokenType::Variable), "Generic variables not allowed here.");
throw CompilerError(stream_.consumeToken(TokenType::Variable), "Generic variables not allowed here.");
}

bool optional = false;
if (stream_.consumeTokenIf(E_CANDY)) {
optional = true;
Expand All @@ -35,10 +37,10 @@ ParsedTypeName AbstractParser::parseTypeName() {
}

Type AbstractParser::parseTypeDeclarative(TypeContext ct, TypeDynamism dynamism, Type expectation,
TypeDynamism *dynamicType, bool allowProtocolsUsingSelf) {
TypeDynamism *dynamicType, bool allowProtocolsUsingSelf) {
if (stream_.nextTokenIs(E_MEDIUM_BLACK_CIRCLE)) {
if (expectation.type() == TypeContent::Nothingness) {
throw CompilerErrorException(stream_.consumeToken(), "Cannot infer ⚫️.");
throw CompilerError(stream_.consumeToken(), "Cannot infer ⚫️.");
}
stream_.consumeToken();
return expectation.copyWithoutOptional();
Expand All @@ -47,23 +49,24 @@ Type AbstractParser::parseTypeDeclarative(TypeContext ct, TypeDynamism dynamism,
auto &token = stream_.consumeToken();
Type type = parseTypeDeclarative(ct, dynamism, expectation, dynamicType, allowProtocolsUsingSelf);
if (!type.allowsMetaType() || type.meta()) {
throw CompilerErrorException(token, "Meta type of %s is restricted.", type.toString(ct, true).c_str());
throw CompilerError(token, "Meta type of %s is restricted.", type.toString(ct, true).c_str());
}
type.setMeta(true);
return type;
}

bool optional = false;
if (stream_.consumeTokenIf(E_CANDY)) {
optional = true;
}

if ((dynamism & TypeDynamism::GenericTypeVariables) != TypeDynamism::None && (ct.calleeType().canHaveGenericArguments()|| ct.function()) &&

if ((dynamism & TypeDynamism::GenericTypeVariables) != TypeDynamism::None &&
(ct.calleeType().canHaveGenericArguments() || ct.function()) &&
stream_.nextTokenIs(TokenType::Variable)) {
if (dynamicType) *dynamicType = TypeDynamism::GenericTypeVariables;

auto &variableToken = stream_.consumeToken(TokenType::Variable);

if (ct.function()) {
auto it = ct.function()->genericArgumentVariables.find(variableToken.value());
if (it != ct.function()->genericArgumentVariables.end()) {
Expand All @@ -78,32 +81,32 @@ Type AbstractParser::parseTypeDeclarative(TypeContext ct, TypeDynamism dynamism,
return type;
}
}
throw CompilerErrorException(variableToken, "No such generic type variable \"%s\".",

throw CompilerError(variableToken, "No such generic type variable \"%s\".",
variableToken.value().utf8().c_str());
}
else if (stream_.nextTokenIs(E_DOG)) {
auto &ratToken = stream_.consumeToken(TokenType::Identifier);
if ((dynamism & TypeDynamism::Self) == TypeDynamism::None) {
throw CompilerErrorException(ratToken, "🐕 not allowed here.");
throw CompilerError(ratToken, "🐕 not allowed here.");
}
if (dynamicType) *dynamicType = TypeDynamism::Self;
return Type(TypeContent::Self, optional);
return Type::self(optional);
}
else if (stream_.consumeTokenIf(E_GRAPES)) {
if (dynamicType) *dynamicType = TypeDynamism::None;

Type t(TypeContent::Callable, optional);
Type t = Type::callableIncomplete(optional);
t.genericArguments.push_back(Type::nothingness());

while (stream_.nextTokenIsEverythingBut(E_WATERMELON) && stream_.nextTokenIsEverythingBut(E_RIGHTWARDS_ARROW)) {
t.genericArguments.push_back(parseTypeDeclarative(ct, dynamism));
}

if (stream_.consumeTokenIf(E_RIGHTWARDS_ARROW)) {
t.genericArguments[0] = parseTypeDeclarative(ct, dynamism);
}

stream_.requireIdentifier(E_WATERMELON);
return t;
}
Expand All @@ -115,19 +118,19 @@ Type AbstractParser::parseTypeDeclarative(TypeContext ct, TypeDynamism dynamism,

auto type = Type::nothingness();
if (!package_->fetchRawType(parsedType, &type)) {
throw CompilerErrorException(parsedType.token, "Could not find type %s in enamespace %s.",
throw CompilerError(parsedType.token, "Could not find type %s in enamespace %s.",
parsedType.name.utf8().c_str(), parsedType.ns.utf8().c_str());
}

parseGenericArgumentsForType(&type, ct, dynamism, parsedType.token);

if (!allowProtocolsUsingSelf && type.type() == TypeContent::Protocol && type.protocol()->usesSelf()) {
auto typeStr = type.toString(ct, true);
throw CompilerErrorException(parsedType.token,
throw CompilerError(parsedType.token,
"Protocol %s can only be used as a generic constraint because it uses 🐓.",
typeStr.c_str());
}

return type;
}
}
Expand All @@ -138,35 +141,35 @@ void AbstractParser::parseGenericArgumentsForType(Type *type, TypeContext ct, Ty
auto typeDef = type->typeDefinitionFunctional();
auto offset = typeDef->numberOfGenericArgumentsWithSuperArguments() - typeDef->numberOfOwnGenericArguments();
type->genericArguments = std::vector<Type>(typeDef->superGenericArguments());

if (typeDef->numberOfOwnGenericArguments()) {
int count = 0;
while (stream_.nextTokenIs(E_SPIRAL_SHELL)) {
auto &token = stream_.consumeToken(TokenType::Identifier);

Type ta = parseTypeDeclarative(ct, dynamism, Type::nothingness(), nullptr);

auto i = count + offset;
if (typeDef->numberOfGenericArgumentsWithSuperArguments() <= i) {
auto name = type->toString(ct, true);
throw CompilerErrorException(token, "Too many generic arguments provided for %s.", name.c_str());
throw CompilerError(token, "Too many generic arguments provided for %s.", name.c_str());
}
if (!ta.compatibleTo(typeDef->genericArgumentConstraints()[i], ct)) {
auto thisName = typeDef->genericArgumentConstraints()[i].toString(ct, true);
auto thatName = ta.toString(ct, true);
throw CompilerErrorException(token, "Generic argument for %s is not compatible to constraint %s.",
thatName.c_str(), thisName.c_str());
throw CompilerError(token, "Generic argument for %s is not compatible to constraint %s.",
thatName.c_str(), thisName.c_str());
}

type->genericArguments.push_back(ta);

count++;
}

if (count != typeDef->numberOfOwnGenericArguments()) {
auto str = type->toString(Type::nothingness(), true);
throw CompilerErrorException(errorToken, "Type %s requires %d generic arguments, but %d were given.",
str.c_str(), typeDef->numberOfOwnGenericArguments(), count);
throw CompilerError(errorToken, "Type %s requires %d generic arguments, but %d were given.",
str.c_str(), typeDef->numberOfOwnGenericArguments(), count);
}
}
}
Expand All @@ -175,31 +178,31 @@ void AbstractParser::parseGenericArgumentsForType(Type *type, TypeContext ct, Ty
bool AbstractParser::parseArgumentList(Callable *c, TypeContext ct, bool initializer) {
bool usedSelf = false;
bool argumentToVariable;

while ((argumentToVariable = stream_.nextTokenIs(E_BABY_BOTTLE)) || stream_.nextTokenIs(TokenType::Variable)) {
if (argumentToVariable) {
auto &token = stream_.consumeToken(TokenType::Identifier);
if (!initializer) {
throw CompilerErrorException(token, "🍼 can only be used with initializers.");
throw CompilerError(token, "🍼 can only be used with initializers.");
}
}

TypeDynamism dynamism;
auto &variableToken = stream_.consumeToken(TokenType::Variable);
auto type = parseTypeDeclarative(ct, TypeDynamism::AllKinds, Type::nothingness(), &dynamism);

c->arguments.push_back(Argument(variableToken, type));

if (dynamism == TypeDynamism::Self) {
usedSelf = true;
}
if (argumentToVariable) {
static_cast<Initializer *>(c)->addArgumentToVariable(variableToken.value());
}
}

if (c->arguments.size() > UINT8_MAX) {
throw CompilerErrorException(c->position(), "A function cannot take more than 255 arguments.");
throw CompilerError(c->position(), "A function cannot take more than 255 arguments.");
}
return usedSelf;
}
Expand All @@ -220,16 +223,16 @@ bool AbstractParser::parseReturnType(Callable *c, TypeContext ct) {
void AbstractParser::parseGenericArgumentsInDefinition(Function *p, TypeContext ct) {
while (stream_.consumeTokenIf(E_SPIRAL_SHELL)) {
auto &variable = stream_.consumeToken(TokenType::Variable);

Type t = parseTypeDeclarative(p->owningType(), TypeDynamism::GenericTypeVariables, Type::nothingness(), nullptr,
true);
p->genericArgumentConstraints.push_back(t);

Type rType = Type(TypeContent::LocalReference, false, static_cast<int>(p->genericArgumentVariables.size()),
nullptr);

if (p->genericArgumentVariables.count(variable.value())) {
throw CompilerErrorException(variable, "A generic argument variable with the same name is already in use.");
throw CompilerError(variable, "A generic argument variable with the same name is already in use.");
}
p->genericArgumentVariables.insert(std::map<EmojicodeString, Type>::value_type(variable.value(), rType));
}
Expand All @@ -239,12 +242,12 @@ void AbstractParser::parseBody(Function *p, bool allowNative) {
if (stream_.nextTokenIs(E_RADIO)) {
auto &radio = stream_.consumeToken(TokenType::Identifier);
if (!allowNative) {
throw CompilerErrorException(radio, "Native code is not allowed in this context.");
throw CompilerError(radio, "Native code is not allowed in this context.");
}
auto &indexToken = stream_.consumeToken(TokenType::Integer);
auto index = std::stoll(indexToken.value().utf8(), 0, 0);
if (index < 1 || index > UINT16_MAX) {
throw CompilerErrorException(indexToken.position(), "Linking Table Index is not in range.");
throw CompilerError(indexToken.position(), "Linking Table Index is not in range.");
}
p->setLinkingTableIndex(static_cast<int>(index));
}
Expand All @@ -256,7 +259,7 @@ void AbstractParser::parseBody(Function *p, bool allowNative) {

void AbstractParser::parseBody(Callable *p) {
p->setTokenStream(stream_);

int depth = 0;
while (true) {
auto &token = stream_.consumeToken();
Expand Down
8 changes: 4 additions & 4 deletions EmojicodeCompiler/AbstractParser.hpp
Expand Up @@ -15,8 +15,8 @@
#include "Function.hpp"

struct ParsedTypeName {
ParsedTypeName(EmojicodeString name, EmojicodeString ns, bool optional, const Token& token) :
name(name), ns(ns), optional(optional), token(token) {}
ParsedTypeName(EmojicodeString name, EmojicodeString ns, bool optional, const Token& token)
: name(name), ns(ns), optional(optional), token(token) {}
EmojicodeString name;
EmojicodeString ns;
bool optional;
Expand All @@ -28,13 +28,13 @@ class AbstractParser {
AbstractParser(Package *pkg, TokenStream stream) : package_(pkg), stream_(stream) {};
Package *package_;
TokenStream stream_;

/** Reads a type name and stores it into the given pointers. */
ParsedTypeName parseTypeName();
/** Reads a type name and stores it into the given pointers. */
Type parseTypeDeclarative(TypeContext tc, TypeDynamism dynamism, Type expectation = Type::nothingness(),
TypeDynamism *dynamicType = nullptr, bool allowProtocolsUsingSelf = false);

/**
* Parses the arguments for a callable.
* @return Whether self was used.
Expand Down
2 changes: 1 addition & 1 deletion EmojicodeCompiler/Callable.cpp
Expand Up @@ -9,7 +9,7 @@
#include "Callable.hpp"

Type Callable::type() const {
Type t(TypeContent::Callable, false);
Type t = Type::callableIncomplete();
t.genericArguments.push_back(returnType);
for (int i = 0; i < arguments.size(); i++) {
t.genericArguments.push_back(arguments[i].type);
Expand Down
16 changes: 8 additions & 8 deletions EmojicodeCompiler/Callable.hpp
Expand Up @@ -16,30 +16,30 @@

struct Argument {
Argument(const Token &n, Type t) : name(n), type(t) {}

/** The name of the variable */
const Token &name;
/** The type */
Type type;
};

/** A callable is a self-containing piece of code that can be executed, "called", and returns a value. Methods, class
methods and closures are examples of callables. */
/** A callable is a self-containing piece of code that can be executed, "called", and returns a value. Methods, class
methods and closures are examples of callables. */
class Callable {
public:
Callable(SourcePosition p) : position_(p) {};
explicit Callable(SourcePosition p) : position_(p) {};

std::vector<Argument> arguments;
/** Return type of the method */
Type returnType = Type::nothingness();

/** Returns the position at which this callable was defined. */
const SourcePosition& position() const { return position_; }

/** Returns a copy of the token stream intended to be used to parse this callable. */
TokenStream tokenStream() const { return tokenStream_; }
void setTokenStream(TokenStream ts) { tokenStream_ = ts; }

/** The type of this callable when used as value. */
virtual Type type() const;
private:
Expand Down

0 comments on commit 927d4d5

Please sign in to comment.