Type ASTSuperMethod::analyse(SemanticAnalyser *analyser, const TypeExpectation &expectation) { if (analyser->function()->functionType() != FunctionType::ObjectMethod) { throw CompilerError(position(), "Not within an object-context."); } Class *superclass = analyser->typeContext().calleeType().eclass()->superclass(); if (superclass == nullptr) { throw CompilerError(position(), "Class has no superclass."); } Function *method = superclass->getMethod(name_, Type(superclass, false), analyser->typeContext(), position()); calleeType_ = Type(superclass, true); return analyser->analyseFunctionCall(&args_, calleeType_, method); }
void Application::analyse(Package *underscorePackage) { underscorePackage->analyse(); if (!hasStartFlagFunction()) { throw CompilerError(underscorePackage->position(), "No 🏁 block was found."); } }
void GLShader::compile(Type shaderType, IByteArray const &source) { #ifndef LIBGUI_GLES2 // With non-ES OpenGL, ignore the precision attributes. static QByteArray prefix("#ifndef GL_ES\n#define lowp\n#define mediump\n#define highp\n#endif\n"); #endif DENG2_ASSERT(shaderType == Vertex || shaderType == Fragment); setState(NotReady); // Keep a copy of the source for possible recompilation. d->compiledSource = source; d->type = shaderType; d->alloc(); // Additional predefined symbols for the shader. QByteArray predefs; if (shaderType == Vertex) { predefs = QByteArray("#define DENG_VERTEX_SHADER\n"); } else { predefs = QByteArray("#define DENG_FRAGMENT_SHADER\n"); } // Prepare the shader source. This would be the time to substitute any // remaining symbols in the shader source. Block src = prefixToSource(source, prefix + predefs); char const *srcPtr = src.constData(); LIBGUI_GL.glShaderSource(d->name, 1, &srcPtr, 0); LIBGUI_GL.glCompileShader(d->name); // Check the compilation status. GLint status; LIBGUI_GL.glGetShaderiv(d->name, GL_COMPILE_STATUS, &status); if (!status) { dint32 logSize = 0; dint32 count = 0; LIBGUI_GL.glGetShaderiv(d->name, GL_INFO_LOG_LENGTH, &logSize); Block log(logSize); LIBGUI_GL.glGetShaderInfoLog(d->name, logSize, &count, reinterpret_cast<GLchar *>(log.data())); throw CompilerError("GLShader::compile", "Compilation of " + String(d->type == Fragment? "fragment" : "vertex") + " shader failed:\n" + log); } setState(Ready); }
Type ASTCallableCall::analyse(SemanticAnalyser *analyser, const TypeExpectation &expectation) { Type type = analyser->expect(TypeExpectation(false, false, false), &callable_); if (type.type() != TypeType::Callable) { throw CompilerError(position(), "Given value is not callable."); } for (size_t i = 1; i < type.genericArguments().size(); i++) { analyser->expectType(type.genericArguments()[i], &args_.arguments()[i - 1]); } return type.genericArguments()[0]; }
void ASTRaise::analyse(SemanticAnalyser *analyser) { analyser->pathAnalyser().recordIncident(PathAnalyserIncident::Returned); if (isOnlyNothingnessReturnAllowed(analyser->function()->functionType())) { auto *initializer = dynamic_cast<Initializer *>(analyser->function()); if (!initializer->errorProne()) { throw CompilerError(position(), "Initializer is not declared error-prone."); } analyser->expectType(initializer->errorType(), &value_); return; } if (analyser->function()->returnType.type() != TypeType::Error) { throw CompilerError(position(), "Function is not declared to return a 🚨."); } boxed_ = analyser->function()->returnType.storageType() == StorageType::Box; analyser->expectType(analyser->function()->returnType.genericArguments()[0], &value_); }
void Token::validate() const { switch (type()) { case TokenType::Integer: if (value().back() == 'x') { throw CompilerError(position(), "Expected a digit after integer literal prefix."); } break; case TokenType::Double: if (value().back() == '.') { throw CompilerError(position(), "Expected a digit after decimal seperator."); } break; case TokenType::Identifier: if (!isValidEmoji(value())) { throw CompilerError(position(), "Invalid emoji."); } default: break; } }
const uint32_t *stream(const Instruction &instr) const { // If we're not going to use any arguments, just return nullptr. // We want to avoid case where we return an out of range pointer // that trips debug assertions on some platforms. if (!instr.length) return nullptr; if (instr.offset + instr.length > spirv.size()) throw CompilerError("Compiler::stream() out of range."); return &spirv[instr.offset]; }
void ASTReturn::analyse(SemanticAnalyser *analyser) { analyser->pathAnalyser().recordIncident(PathAnalyserIncident::Returned); if (analyser->function()->returnType.type() == TypeType::NoReturn) { return; } if (isOnlyNothingnessReturnAllowed(analyser->function()->functionType())) { throw CompilerError(position(), "🍎 cannot be used inside an initializer."); } analyser->expectType(analyser->function()->returnType, &value_); }
void ASTSuperinitializer::analyse(SemanticAnalyser *analyser) { if (!isSuperconstructorRequired(analyser->function()->functionType())) { throw CompilerError(position(), "🐐 can only be used inside initializers."); } if (analyser->typeContext().calleeType().eclass()->superclass() == nullptr) { throw CompilerError(position(), "🐐 can only be used if the class inherits from another."); } if (analyser->pathAnalyser().hasPotentially(PathAnalyserIncident::CalledSuperInitializer)) { analyser->app()->error(CompilerError(position(), "Superinitializer might have already been called.")); } analyser->scoper().instanceScope()->unintializedVariablesCheck(position(), "Instance variable \"", "\" must be " "initialized before calling the superinitializer."); Class *eclass = analyser->typeContext().calleeType().eclass(); auto initializer = eclass->superclass()->getInitializer(name_, Type(eclass, false), analyser->typeContext(), position()); superType_ = Type(eclass->superclass(), false); analyser->analyseFunctionCall(&arguments_, superType_, initializer); analyser->pathAnalyser().recordIncident(PathAnalyserIncident::CalledSuperInitializer); }
Type ASTConditionalAssignment::analyse(SemanticAnalyser *analyser, const TypeExpectation &expectation) { Type t = analyser->expect(TypeExpectation(false, false), &expr_); if (!t.optional()) { throw CompilerError(position(), "Condition assignment can only be used with optionals."); } t.setReference(false); t.setOptional(false); auto &variable = analyser->scoper().currentScope().declareVariable(varName_, t, true, position()); variable.initialize(); varId_ = variable.id(); return Type::boolean(); }
Package* Application::loadPackage(const std::string &name, const SourcePosition &p, Package *requestor) { if (auto package = findPackage(name)) { if (!package->finishedLoading()) { throw CompilerError(p, "Circular dependency detected: ", requestor->name(), " and ", name, " depend on each other."); } return package; } auto path = packageDirectory_ + "/" + name + "/header.emojic"; auto package = std::make_unique<Package>(name, path, this); auto rawPtr = package.get(); packages_.emplace(name, rawPtr); packagesLoadingOrder_.emplace_back(std::move(package)); rawPtr->parse(); rawPtr->analyse(); return rawPtr; }
void CompilerContext::appendInlineAssembly( string const& _assembly, vector<string> const& _localVariables, map<string, string> const& _replacements ) { string replacedAssembly; string const* assembly = &_assembly; if (!_replacements.empty()) { replacedAssembly = _assembly; for (auto const& replacement: _replacements) replacedAssembly = boost::algorithm::replace_all_copy(replacedAssembly, replacement.first, replacement.second); assembly = &replacedAssembly; } unsigned startStackHeight = stackHeight(); auto identifierAccess = [&]( assembly::Identifier const& _identifier, eth::Assembly& _assembly, assembly::CodeGenerator::IdentifierContext _context ) { auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); if (it == _localVariables.end()) return false; unsigned stackDepth = _localVariables.end() - it; int stackDiff = _assembly.deposit() - startStackHeight + stackDepth; if (stackDiff < 1 || stackDiff > 16) BOOST_THROW_EXCEPTION( CompilerError() << errinfo_comment("Stack too deep, try removing local variables.") ); if (_context == assembly::CodeGenerator::IdentifierContext::RValue) _assembly.append(dupInstruction(stackDiff)); else { _assembly.append(swapInstruction(stackDiff)); _assembly.append(Instruction::POP); } return true; }; solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, m_asm, identifierAccess), ""); }
Type ASTCast::analyse(SemanticAnalyser *analyser, const TypeExpectation &expectation) { auto type = analyser->analyseTypeExpr(typeExpr_, expectation); Type originalType = value_->analyse(analyser, expectation); if (originalType.compatibleTo(type, analyser->typeContext())) { analyser->app()->error(CompilerError(position(), "Unnecessary cast.")); } else if (!type.compatibleTo(originalType, analyser->typeContext())) { auto typeString = type.toString(analyser->typeContext()); analyser->app()->error(CompilerError(position(), "Cast to unrelated type ", typeString," will always fail.")); } if (type.type() == TypeType::Class) { if (!type.genericArguments().empty()) { analyser->app()->error(CompilerError(position(), "Class casts with generic arguments are not available.")); } if (originalType.type() == TypeType::Someobject || originalType.type() == TypeType::Class) { if (originalType.optional()) { throw CompilerError(position(), "Downcast on classes with optionals not possible."); } castType_ = CastType::ClassDowncast; assert(originalType.storageType() == StorageType::Simple && originalType.size() == 1); } else { castType_ = CastType::ToClass; assert(originalType.storageType() == StorageType::Box); } } else if (type.type() == TypeType::Protocol && isStatic(typeExpr_->availability())) { if (!type.genericArguments().empty()) { analyser->app()->error(CompilerError(position(), "Cannot cast to generic protocols.")); } castType_ = CastType::ToProtocol; assert(originalType.storageType() == StorageType::Box); } else if ((type.type() == TypeType::ValueType || type.type() == TypeType::Enum) && isStatic(typeExpr_->availability())) { castType_ = CastType::ToValueType; assert(originalType.storageType() == StorageType::Box); type.forceBox(); } else { auto typeString = type.toString(analyser->typeContext()); throw CompilerError(position(), "You cannot cast to ", typeString, "."); } type.setOptional(true); return type; }
Type ASTTypeMethod::analyse(SemanticAnalyser *analyser, const TypeExpectation &expectation) { auto type = analyser->analyseTypeExpr(callee_, expectation); if (type.optional()) { analyser->app()->warn(position(), "You cannot call optionals on 🍬."); } Function *method; if (type.type() == TypeType::Class) { method = type.typeDefinition()->getTypeMethod(name_, type, analyser->typeContext(), position()); } else if ((type.type() == TypeType::ValueType || type.type() == TypeType::Enum) && isStatic(callee_->availability())) { method = type.typeDefinition()->getTypeMethod(name_, type, analyser->typeContext(), position()); valueType_ = true; } else { throw CompilerError(position(), "You can’t call type methods on ", type.toString(analyser->typeContext()), "."); } return analyser->analyseFunctionCall(&args_, type, method); }
void ASTErrorHandler::analyse(SemanticAnalyser *analyser) { Type type = analyser->expect(TypeExpectation(false, false), &value_); if (type.type() != TypeType::Error) { throw CompilerError(position(), "🥑 can only be used with 🚨."); } analyser->scoper().pushScope(); auto &var = analyser->scoper().currentScope().declareInternalVariable(type, position()); analyser->pathAnalyser().beginBranch(); analyser->scoper().pushScope(); valueIsBoxed_ = type.storageType() == StorageType::Box; valueType_ = type.genericArguments()[1]; if (valueIsBoxed_) { valueType_.forceBox(); } analyser->scoper().currentScope().declareVariableWithId(valueVarName_, valueType_, true, var.id(), position()).initialize(); var.initialize(); varId_ = var.id(); valueBlock_.analyse(analyser); analyser->scoper().popScope(analyser->app()); analyser->pathAnalyser().endBranch(); analyser->pathAnalyser().beginBranch(); analyser->scoper().pushScope(); analyser->scoper().currentScope().declareVariableWithId(errorVarName_, type.genericArguments()[0], true, var.id(), position()).initialize(); errorBlock_.analyse(analyser); analyser->scoper().popScope(analyser->app()); analyser->pathAnalyser().endBranch(); analyser->pathAnalyser().endMutualExclusiveBranches(); analyser->scoper().popScope(analyser->app()); }
void ASTForIn::analyse(SemanticAnalyser *analyser) { analyser->scoper().pushScope(); Type iteratee = analyser->expect(TypeExpectation(true, true, false), &iteratee_); analyser->popTemporaryScope(iteratee_); elementType_ = Type::noReturn(); if (!analyser->typeIsEnumerable(iteratee, &elementType_)) { auto iterateeString = iteratee.toString(analyser->typeContext()); throw CompilerError(position(), iterateeString, " does not conform to s🔂."); } iteratee_->setExpressionType(Type(PR_ENUMERATEABLE, false)); analyser->pathAnalyser().beginBranch(); iteratorVar_ = analyser->scoper().currentScope().declareInternalVariable(elementType_, position()).id(); auto &elVar = analyser->scoper().currentScope().declareVariable(varName_, elementType_, true, position()); elVar.initialize(); elementVar_ = elVar.id(); block_.analyse(analyser); analyser->scoper().popScope(analyser->app()); analyser->pathAnalyser().endBranch(); analyser->pathAnalyser().endUncertainBranches(); }
void disallow() const { if (found_) { throw CompilerError(position_, "Misplaced documentation token."); } }