TEST(TestDeclaration, testLet) { PARSE_STATEMENT(L"let a : Int[] = [1, 2, 3]"); ValueBindingsPtr c; IdentifierPtr id; ValueBindingPtr a; ArrayLiteralPtr value; ArrayTypePtr type; TypeIdentifierPtr Int; ASSERT_NOT_NULL(c = std::dynamic_pointer_cast<ValueBindings>(root)); ASSERT_TRUE(c->isReadOnly()); ASSERT_EQ(1, c->numBindings()); ASSERT_NOT_NULL(a = c->get(0)); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(a->getName())); ASSERT_EQ(L"a", id->getIdentifier()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<ArrayType>(a->getDeclaredType())); ASSERT_NOT_NULL(Int = std::dynamic_pointer_cast<TypeIdentifier>(type->getInnerType())); ASSERT_EQ(L"Int", Int->getName()); ASSERT_NOT_NULL(value = std::dynamic_pointer_cast<ArrayLiteral>(c->get(0)->getInitializer())); ASSERT_EQ(3, value->numElements()); ASSERT_EQ(L"1", std::dynamic_pointer_cast<IntegerLiteral>(value->getElement(0))->valueAsString); ASSERT_EQ(L"2", std::dynamic_pointer_cast<IntegerLiteral>(value->getElement(1))->valueAsString); ASSERT_EQ(L"3", std::dynamic_pointer_cast<IntegerLiteral>(value->getElement(2))->valueAsString); }
TEST(TestDeclaration, testVar_Multiple) { PARSE_STATEMENT(L"var x = 0.0, y = 0.0, z = 0.0"); ValueBindingsPtr vars; ValueBindingPtr var; IdentifierPtr id; FloatLiteralPtr f; ASSERT_NOT_NULL(vars = std::dynamic_pointer_cast<ValueBindings>(root)); ASSERT_TRUE(!vars->isReadOnly()); ASSERT_EQ(3, vars->numBindings()); ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ValueBinding>(vars->get(0))); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(var->getName())); ASSERT_EQ(L"x", id->getIdentifier()); ASSERT_NOT_NULL(f = std::dynamic_pointer_cast<FloatLiteral>(var->getInitializer())); ASSERT_EQ(L"0.0", f->valueAsString); ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ValueBinding>(vars->get(1))); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(var->getName())); ASSERT_EQ(L"y", id->getIdentifier()); ASSERT_NOT_NULL(f = std::dynamic_pointer_cast<FloatLiteral>(var->getInitializer())); ASSERT_EQ(L"0.0", f->valueAsString); ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ValueBinding>(vars->get(2))); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(var->getName())); ASSERT_EQ(L"z", id->getIdentifier()); ASSERT_NOT_NULL(f = std::dynamic_pointer_cast<FloatLiteral>(var->getInitializer())); ASSERT_EQ(L"0.0", f->valueAsString); }
IdentifierPtr CNodeManager::create(const string& name) { auto pos = identMap.find(name); if(pos != identMap.end()) { return pos->second; } IdentifierPtr res = new Identifier(name); res->setManager(this); identMap.insert(std::make_pair(name, res)); return res; }
void loadDependent(ModulePtr m, vector<string> *sourceFiles, ImportPtr dependent, bool verbose) { ImportPtr x = dependent; x->module = loadModuleByName(x->dottedName, sourceFiles, verbose); switch (x->importKind) { case IMPORT_MODULE : { ImportModule *im = (ImportModule *)x.ptr(); IdentifierPtr name = NULL; if (im->alias.ptr()) { name = im->alias; m->importedModuleNames[im->alias->str].module = x->module; } else { llvm::ArrayRef<IdentifierPtr> parts = im->dottedName->parts; if (parts.size() == 1) name = parts[0]; else if (x->visibility == PUBLIC) error(x->location, "public imports of dotted module paths must have an \"as <name>\" alias"); llvm::StringMap<ModuleLookup> *node = &m->importedModuleNames; for (size_t i = parts.size() - 1; i >= 1; --i) { node = &(*node)[parts[i]->str].parents; } (*node)[parts[0]->str].module = x->module; } if (name.ptr()) { string nameStr(name->str.begin(), name->str.end()); if (m->importedNames.count(nameStr)) error(name, "name imported already: " + nameStr); m->importedNames.insert(nameStr); m->allSymbols[nameStr].insert(x->module.ptr()); if (x->visibility == PUBLIC) m->publicSymbols[nameStr].insert(x->module.ptr()); } break; } case IMPORT_STAR : break; case IMPORT_MEMBERS : { ImportMembers *y = (ImportMembers *)x.ptr(); for (unsigned i = 0; i < y->members.size(); ++i) { ImportedMember &z = y->members[i]; IdentifierPtr alias = z.alias.ptr() ? z.alias : z.name; string aliasStr(alias->str.begin(), alias->str.end()); if (m->importedNames.count(aliasStr)) error(alias, "name imported already: " + aliasStr); assert(y->aliasMap.count(aliasStr) == 0); m->importedNames.insert(aliasStr); y->aliasMap[aliasStr] = z.name; } break; } default : assert(false); } }
void Union:: type (IdentifierPtr const& id) { if (ctx.trace ()) cerr << "type " << id << endl; type_ = 0; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { type_ = &resolve<Type> (from, name); if (!(dynamic_cast<Enum*> (type_) || dynamic_cast<Boolean*> (type_) || dynamic_cast<Char*> (type_) || dynamic_cast<Wchar*> (type_) || dynamic_cast<Short*> (type_) || dynamic_cast<UnsignedShort*> (type_) || dynamic_cast<Long*> (type_) || dynamic_cast<UnsignedLong*> (type_) || dynamic_cast<LongLong*> (type_) || dynamic_cast<UnsignedLongLong*> (type_))) { throw WrongType (type_->scoped_name ()); } ctx.tu ().new_edge<ArgumentsWithType> (*type_, now ()); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid union declaration" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no type with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not a valid discriminant type" << endl; } }
void Typedef:: begin_unbounded_seq (IdentifierPtr const& id) { if (ctx.trace ()) cerr << "typedef u-sequence<" << id << ">" << endl; define_ = true; type_ = 0; array_type_ = 0; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { Type& t (resolve<Type> (from, name)); UnboundedSequence& s ( ctx.tu ().new_node<UnboundedSequence> ( ctx.file (), line_)); ctx.tu ().new_edge<ArgumentsWithType> (t, s); type_ = &s; } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid sequence declaration" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no type with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not a type declaration" << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "using non-type in sequence specialization is illegal" << endl; } }
void convertFreeVars(LambdaPtr x, EnvPtr env, const string &closureDataName, vector<string> &freeVars) { EnvPtr env2 = new Env(env); for (unsigned i = 0; i < x->formalArgs.size(); ++i) { IdentifierPtr name = x->formalArgs[i]; addLocal(env2, name, name.ptr()); } if (x->formalVarArg.ptr()) { addLocal(env2, x->formalVarArg, x->formalVarArg.ptr()); } LambdaContext ctx(x->captureByRef, env, closureDataName, freeVars); convertFreeVars(x->body, env2, ctx); }
TEST(TestFunc, testFunc) { PARSE_STATEMENT(L"func stepForward(input: Int) -> Int {" L"return input + 1" L"}"); FunctionDefPtr func; ParametersNodePtr params; ParameterNodePtr param; TypeIdentifierPtr type; CodeBlockPtr cb; ReturnStatementPtr ret; BinaryOperatorPtr add; IdentifierPtr id; IntegerLiteralPtr i; ASSERT_NOT_NULL(func = std::dynamic_pointer_cast<FunctionDef>(root)); ASSERT_EQ(L"stepForward", func->getName()); ASSERT_EQ(1, func->numParameters()); ASSERT_NOT_NULL(params = func->getParameters(0)); ASSERT_EQ(1, params->numParameters()); ASSERT_NOT_NULL(param = params->getParameter(0)); ASSERT_EQ(ParameterNode::None, param->getAccessibility()); ASSERT_FALSE(param->isShorthandExternalName()); ASSERT_FALSE(param->isInout()); ASSERT_NULL(param->getDefaultValue()); ASSERT_EQ(L"", param->getExternalName()); ASSERT_EQ(L"input", param->getLocalName()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(param->getDeclaredType())); ASSERT_EQ(L"Int", type->getName()); ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(func->getReturnType())); ASSERT_EQ(L"Int", type->getName()); ASSERT_NOT_NULL(cb = func->getBody()); ASSERT_EQ(1, cb->numStatements()); ASSERT_NOT_NULL(ret = std::dynamic_pointer_cast<ReturnStatement>(cb->getStatement(0))); ASSERT_NOT_NULL(add = std::dynamic_pointer_cast<BinaryOperator>(ret->getExpression())); ASSERT_EQ(L"+", add->getOperator()); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(add->getLHS())); ASSERT_NOT_NULL(i = std::dynamic_pointer_cast<IntegerLiteral>(add->getRHS())); ASSERT_EQ(L"input", id->getIdentifier()); ASSERT_EQ(L"1", i->valueAsString); }
void EventTypeFactory:: raises (IdentifierPtr const& id) { if (ctx.trace ()) cerr << "raises " << id << endl; if (f_ == 0) return; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { SemanticGraph::Exception& e ( resolve<SemanticGraph::Exception> (from, name)); ctx.tu ().new_edge<Raises> (*f_, e); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid raises declaration" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no exception with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not an exception declaration" << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "using non-exception type in raises declaration is " << "illegal" << endl; } }
void Typedef:: begin (IdentifierPtr const& id) { if (ctx.trace ()) cerr << "typedef " << id << endl; define_ = false; type_ = 0; array_type_ = 0; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { type_ = &resolve<Type> (from, name); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid typedef declaration" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no type with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not a type declaration" << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "using non-type in typedef is illegal" << endl; } }
void Component:: supports (IdentifierPtr const& id) { if (ctx.trace ()) cerr << " supports " << id << endl; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { SemanticGraph::Interface& i ( resolve<SemanticGraph::Interface> (from, name, Flags::defined)); check_support (now ().supports_begin (), now ().supports_end (), i); ctx.tu ().new_edge<Supports> (now (), i); ctx.tu ().new_edge<Extends> (now (), i); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid supports specification" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no interface with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "incompatible type in supports specification" << endl; } catch (NotDefined const& e) { cerr << ctx.file () << ":" << id->line () << ": error: " << "attempt to support forward-declared interface " << e.name () << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "support of forward-declared interface is illegal" << endl; } catch (AlreadySupported const& e) { cerr << ctx.file () << ":" << id->line () << ": error: " << "directly supporting interface \'" << e.name () << "\' more than once is illegal" << endl; } }
TEST(TestDeclaration, testVar) { PARSE_STATEMENT(L"var currentLoginAttempt = 0"); ValueBindingsPtr vars; ValueBindingPtr var; IdentifierPtr id; IntegerLiteralPtr i; ASSERT_NOT_NULL(vars = std::dynamic_pointer_cast<ValueBindings>(root)); ASSERT_TRUE(!vars->isReadOnly()); ASSERT_EQ(1, vars->numBindings()); ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ValueBinding>(vars->get(0))); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(var->getName())); ASSERT_EQ(L"currentLoginAttempt", id->getIdentifier()); ASSERT_NOT_NULL(i = std::dynamic_pointer_cast<IntegerLiteral>(var->getInitializer())); ASSERT_EQ(L"0", i->valueAsString); }
TEST(TestDeclaration, testVar_Typed) { PARSE_STATEMENT(L"var welcomeMessage: String"); ValueBindingsPtr vars; ValueBindingPtr var; IdentifierPtr id; TypeIdentifierPtr t; ASSERT_NOT_NULL(vars = std::dynamic_pointer_cast<ValueBindings>(root)); ASSERT_TRUE(!vars->isReadOnly()); ASSERT_EQ(1, vars->numBindings()); ASSERT_NOT_NULL(var = std::dynamic_pointer_cast<ValueBinding>(vars->get(0))); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(var->getName())); ASSERT_EQ(L"welcomeMessage", id->getIdentifier()); ASSERT_NOT_NULL(t = std::dynamic_pointer_cast<TypeIdentifier>(var->getDeclaredType())); ASSERT_EQ(L"String", t->getName()); }
void Publishes:: type (IdentifierPtr const& id) { if (ctx.trace ()) cerr << "publishes " << id; type_ = 0; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { type_ = &resolve<EventType> (from, name); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid publishes declaration" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no eventtype with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not an eventtype declaration" << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "using non-eventtype in publishes declaration is illegal" << endl; } }
TEST(TestDeclaration, testLet_Multiple) { PARSE_STATEMENT(L"let a=[k1 : 1, k2 : 2], b : Int = 2"); ValueBindingsPtr c; ValueBindingPtr b; IdentifierPtr id; TypeIdentifierPtr Int; DictionaryLiteralPtr dict; ASSERT_NOT_NULL(c = std::dynamic_pointer_cast<ValueBindings>(root)); ASSERT_TRUE(c->isReadOnly()); ASSERT_EQ(2, c->numBindings()); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(c->get(0)->getName())); ASSERT_EQ(L"a", id->getIdentifier()); ASSERT_NOT_NULL(dict = std::dynamic_pointer_cast<DictionaryLiteral>(c->get(0)->getInitializer())); ASSERT_EQ(2, dict->numElements()); ASSERT_NOT_NULL(b = c->get(1)); ASSERT_NOT_NULL(id = std::dynamic_pointer_cast<Identifier>(b->getName())); ASSERT_EQ(L"b", id->getIdentifier()); ASSERT_NOT_NULL(Int = std::dynamic_pointer_cast<TypeIdentifier>(b->getDeclaredType())); ASSERT_EQ(L"Int", Int->getName()); }
void EventTypeFactory:: parameter (IdentifierPtr const& type_id, SimpleIdentifierPtr const& name_id) { if (ctx.trace ()) cerr << "parameter in " << " " << type_id << " " << name_id << endl; if (f_ == 0) return; Name name (type_id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { Type& t (resolve<Type> (from, name, Flags::complete)); Parameter& p ( ctx.tu ().new_node<InParameter> ( ctx.file (), name_id->line (), name_id->lexeme ())); ctx.tu ().new_edge<Belongs> (p, t); ctx.tu ().new_edge<Receives> (*f_, p); } catch (Resolve const&) { cerr << ctx.file () << ":" << type_id->line () << ": error: " << "invalid parameter declaration" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << type_id->line () << ": error: " << "no type with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << type_id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not a type declaration" << endl; cerr << ctx.file () << ":" << type_id->line () << ": error: " << "using non-type as an factory parameter type is " << "illegal" << endl; } catch (NotComplete const& e) { cerr << ctx.file () << ":" << type_id->line () << ": error: " << "type \'" << e.name () << "\' is not complete" << endl; } }
void Member:: type (IdentifierPtr const& id) { if (ctx.trace ()) cerr << "member " << id << endl; type_ = 0; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { // With introduction of CORBA 3.1 we have a new beast: // struct with incoplete members which itself becomes // incomplete. // type_ = &resolve<Type> (from, name/*, Flags::complete*/); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid member declaration" << endl; throw; } //@@ I am not handling NotUnique here. For example if // I provide module name as type then the compiler // will ICE. Think about other places it may happen // (attribute, value memebr, typeded, others?). // } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no type with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not a type declaration" << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "using non-type as a member type is illegal" << endl; } catch (NotComplete const& e) { cerr << ctx.file () << ":" << id->line () << ": error: " << "type \'" << e.name () << "\' is not complete" << endl; } }
void Operation:: raises (IdentifierPtr const& id) { if (ctx.trace ()) cerr << "raises " << id << endl; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); struct OneWay : Resolve {}; try { try { if (one_way_) throw OneWay (); SemanticGraph::Exception& e ( resolve<SemanticGraph::Exception> (from, name)); ctx.tu ().new_edge<Raises> (*op_, e); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid raises declaration" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no exception with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not an exception declaration" << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "using non-exception type in raises declaration is " << "illegal" << endl; } catch (OneWay const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "oneway operation may not raise exceptions" << endl; } }
void Component:: inherits (IdentifierPtr const& id) { if (ctx.trace ()) cerr << " inherits " << id << endl; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { SemanticGraph::Component& c ( resolve<SemanticGraph::Component> (from, name, Flags::defined)); ctx.tu ().new_edge<Inherits> (now (), c); ctx.tu ().new_edge<Extends> (now (), c); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid inheritance specification" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no component with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "incompatible type in inheritance specification" << endl; } catch (NotDefined const& e) { cerr << ctx.file () << ":" << id->line () << ": error: " << "attempt to inherit from forward-declared component " << e.name () << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "inheritance from forward-declared component is illegal" << endl; } }
void Operation:: type (IdentifierPtr const& id) { if (ctx.trace ()) cerr << "operation " << id; type_ = 0; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { type_ = &resolve<Type> (from, name, Flags::complete); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid operation declaration" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no type with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not a type declaration" << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "using non-type as an operation return type is illegal" << endl; } catch (NotComplete const& e) { cerr << ctx.file () << ":" << id->line () << ": error: " << "type \'" << e.name () << "\' is not complete" << endl; } }
void SemanticAnalyzer::visitValueBinding(const ValueBindingPtr& node) { PatternPtr name = node->getName(); //tuple was already exploded in declaration analyzer if(name->getNodeType() == NodeType::Tuple) { validateTupleTypeDeclaration(node); } if (name->getNodeType() != NodeType::Identifier) return; if(node->getOwner()->isReadOnly() && !node->getInitializer() && ctx->currentType == nullptr) { error(node, Errors::E_LET_REQUIRES_INITIALIZER); return; } //handle type inference for temporary variable if(node->isTemporary() && node->getInitializer()) { //temporary variable always has an initializer TypePtr initializerType; TypePtr declaredType = node->getType(); SCOPED_SET(ctx->contextualType, declaredType); node->getInitializer()->accept(this); initializerType = node->getInitializer()->getType(); assert(initializerType != nullptr); if(declaredType) { //it has both type definition and initializer, then we need to check if the initializer expression matches the type annotation if(!initializerType->canAssignTo(declaredType)) { error(node, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, initializerType->toString(), declaredType->toString()); return; } } else { node->setType(initializerType); } } //add implicitly constructor for Optional IdentifierPtr id = static_pointer_cast<Identifier>(node->getName()); SymbolScope* currentScope = symbolRegistry->getCurrentScope(); TypePtr declaredType = node->getType() ? node->getType() : lookupType(node->getDeclaredType()); SCOPED_SET(ctx->contextualType, declaredType); if(!declaredType && !node->getInitializer()) { error(node, Errors::E_TYPE_ANNOTATION_MISSING_IN_PATTERN); return; } SymbolPtr sym = currentScope->lookup(id->getIdentifier()); assert(sym != nullptr); SymbolPlaceHolderPtr placeholder = std::dynamic_pointer_cast<SymbolPlaceHolder>(sym); assert(placeholder != nullptr); if(declaredType) { placeholder->setType(declaredType); } ExpressionPtr initializer = node->getInitializer(); if(initializer) { placeholder->setFlags(SymbolFlagInitializing, true); ExpressionPtr initializer = transformExpression(declaredType, node->getInitializer()); node->setInitializer(initializer); TypePtr actualType = initializer->getType(); assert(actualType != nullptr); if(declaredType) { if(!Type::equals(actualType, declaredType) && !canConvertTo(initializer, declaredType)) { error(initializer, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, actualType->toString(), declaredType->toString()); return; } } if(!declaredType) placeholder->setType(actualType); } assert(placeholder->getType() != nullptr); placeholder->setFlags(SymbolFlagInitializing, false); //optional type always considered initialized, compiler will make it has a default value nil TypePtr symbolType = sym->getType(); GlobalScope* global = symbolRegistry->getGlobalScope(); if(initializer || global->isOptional(symbolType) || global->isImplicitlyUnwrappedOptional(symbolType)) markInitialized(placeholder); if (initializer) placeholder->setFlags(SymbolFlagHasInitializer, true); if(node->isTemporary()) { placeholder->setFlags(SymbolFlagTemporary, true); markInitialized(placeholder); } if(!node->isTemporary()) { //check access control level DeclarationType decl = ctx->currentType ? DeclarationTypeProperty : DeclarationTypeVariable; declarationAnalyzer->verifyAccessLevel(node->getOwner(), placeholder->getType(), decl, ComponentTypeType); } if(ctx->currentType && ctx->currentType->getCategory() == Type::Protocol) { error(node, Errors::E_PROTOCOL_VAR_MUST_BE_COMPUTED_PROPERTY_1); } }
static void initializeVariantType(VariantTypePtr t) { assert(!t->initialized); EnvPtr variantEnv = new Env(t->variant->env); { const vector<IdentifierPtr> ¶ms = t->variant->params; IdentifierPtr varParam = t->variant->varParam; assert(params.size() <= t->params.size()); for (unsigned j = 0; j < params.size(); ++j) addLocal(variantEnv, params[j], t->params[j]); if (varParam.ptr()) { MultiStaticPtr ms = new MultiStatic(); for (unsigned j = params.size(); j < t->params.size(); ++j) ms->add(t->params[j]); addLocal(variantEnv, varParam, ms.ptr()); } else { assert(params.size() == t->params.size()); } } ExprListPtr defaultInstances = t->variant->defaultInstances; for (unsigned i = 0; i < defaultInstances->size(); ++i) { ExprPtr x = defaultInstances->exprs[i]; TypePtr memberType = evaluateType(x, variantEnv); t->memberTypes.push_back(memberType); } const vector<InstancePtr> &instances = t->variant->instances; for (unsigned i = 0; i < instances.size(); ++i) { InstancePtr x = instances[i]; vector<PatternCellPtr> cells; vector<MultiPatternCellPtr> multiCells; const vector<PatternVar> &pvars = x->patternVars; EnvPtr patternEnv = new Env(x->env); for (unsigned j = 0; j < pvars.size(); ++j) { if (pvars[j].isMulti) { MultiPatternCellPtr multiCell = new MultiPatternCell(NULL); multiCells.push_back(multiCell); cells.push_back(NULL); addLocal(patternEnv, pvars[j].name, multiCell.ptr()); } else { PatternCellPtr cell = new PatternCell(NULL); cells.push_back(cell); multiCells.push_back(NULL); addLocal(patternEnv, pvars[j].name, cell.ptr()); } } PatternPtr pattern = evaluateOnePattern(x->target, patternEnv); if (!unifyPatternObj(pattern, t.ptr())) continue; EnvPtr staticEnv = new Env(x->env); for (unsigned j = 0; j < pvars.size(); ++j) { if (pvars[j].isMulti) { MultiStaticPtr ms = derefDeep(multiCells[j].ptr()); if (!ms) error(pvars[j].name, "unbound pattern variable"); addLocal(staticEnv, pvars[j].name, ms.ptr()); } else { ObjectPtr v = derefDeep(cells[j].ptr()); if (!v) error(pvars[j].name, "unbound pattern variable"); addLocal(staticEnv, pvars[j].name, v.ptr()); } } if (x->predicate.ptr()) if (!evaluateBool(x->predicate, staticEnv)) continue; TypePtr memberType = evaluateType(x->member, staticEnv); t->memberTypes.push_back(memberType); } RecordPtr reprRecord = getVariantReprRecord(); vector<ObjectPtr> params; for (unsigned i = 0; i < t->memberTypes.size(); ++i) params.push_back(t->memberTypes[i].ptr()); t->reprType = recordType(reprRecord, params); t->initialized = true; }
/* GRAMMAR OF A PATTERN pattern → wildcard-pattern type-annotation opt pattern → identifier-pattern type-annotation opt pattern → value-binding-pattern pattern → tuple-pattern type-annotation opt pattern → enum-case-pattern pattern → type-casting-pattern pattern → expression-pattern */ PatternPtr Parser::parsePattern() { Token token; expect_next(token); if(token.type == TokenType::Identifier) { switch(token.identifier.keyword) { // pattern → wildcard-pattern type-annotationopt // pattern → identifier-pattern type-annotationopt case Keyword::_: { IdentifierPtr id = nodeFactory->createIdentifier(token.state); id->setIdentifier(token.token); if((flags & UNDER_CASE) == 0)//type annotation is not parsed when it's inside a let/var { if(match(L":")) { TypedPatternPtr ret = nodeFactory->createTypedPattern(*id->getSourceInfo()); TypeNodePtr type = parseTypeAnnotation(); ret->setDeclaredType(type); ret->setPattern(id); return ret; } } return id; } // pattern → value-binding-pattern case Keyword::Var: case Keyword::Let: { ValueBindingPatternPtr ret = nodeFactory->createValueBindingPattern(token.state); PatternPtr binding = parsePattern(); if(TypedPatternPtr p = std::dynamic_pointer_cast<TypedPattern>(binding)) { ret->setBinding(p->getPattern()); ret->setDeclaredType(p->getDeclaredType()); } else { ret->setBinding(binding); } ret->setReadOnly(token.identifier.keyword == Keyword::Let); return ret; } default: break; } } restore(token); if(token.type == TokenType::OpenParen) { //pattern → tuple-pattern type-annotation opt TuplePtr ret = std::static_pointer_cast<Tuple>(parseTuple()); if(flags & (UNDER_LET | UNDER_VAR)) { //type-annotation only exists under let/var statement if(match(L":")) { TypeNodePtr type = parseTypeAnnotation(); TypedPatternPtr pattern = nodeFactory->createTypedPattern(*ret->getSourceInfo()); pattern->setDeclaredType(type); pattern->setPattern(ret); return pattern; } } return ret; } if(this->flags & UNDER_SWITCH_CASE) { //the following patterns are only exists in switch/case statement // pattern → enum-case-pattern if(token.type == TokenType::Attribute || token == L".") { return parseEnumPattern(); } // pattern → type-casting-pattern if(token.getKeyword() == Keyword::Is) { return parseTypeCastingPattern(); } } // pattern → expression-pattern PatternPtr ret = parseExpression(); if(this->flags & UNDER_SWITCH_CASE) { if(predicate(L"as")) { restore(token); ret = NULL; return parseTypeCastingPattern(); } } return ret; }
void NodeSerializer::visitIdentifier(const IdentifierPtr& node) { append(node->getIdentifier()); }
/* GRAMMAR OF A VARIABLE DECLARATION variable-declaration → variable-declaration-head pattern-initializer-list variable-declaration → variable-declaration-head variable-name type-annotation code-block variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-block variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-keyword-block variable-declaration → variable-declaration-head variable-name type-annotation initializer opt willSet-didSet-block variable-declaration-head → attributes opt declaration-specifiers opt var variable-name → identifier */ DeclarationPtr Parser::parseVar(const std::vector<AttributePtr>& attrs, int specifiers) { Token token; expect(Keyword::Var, token); Flags flags(this, UNDER_VAR); //try read it as pattern-initializer-list ValueBindingsPtr ret = nodeFactory->createValueBindings(token.state); ret->setReadOnly(false); ret->setAttributes(attrs); ret->setSpecifiers(specifiers); ValueBindingPtr var = parseVariableDeclaration(); var->setSpecifiers(specifiers); ret->add(var); if(predicate(L",")) { while(match(L",")) { var = parseVariableDeclaration(); var->setSpecifiers(specifiers); ret->add(var); } return ret; } if(!match(L"{")) return ret; peek(token); IdentifierPtr name = std::dynamic_pointer_cast<Identifier>(var->getName()); tassert(token, name != nullptr, Errors::E_GETTER_SETTER_CAN_ONLY_BE_DEFINED_FOR_A_SINGLE_VARIABLE, L""); ComputedPropertyPtr prop = nodeFactory->createComputedProperty(*var->getSourceInfo()); prop->setAttributes(attrs); prop->setSpecifiers(specifiers); prop->setTypeAttributes(var->getTypeAttributes()); prop->setName(name->getIdentifier()); prop->setDeclaredType(var->getDeclaredType()); prop->setInitializer(var->getInitializer()); var = nullptr; ret = nullptr; if(token.type != TokenType::CloseBrace) { Flags flags(this, SUPPRESS_TRAILING_CLOSURE); switch(token.getKeyword()) { case Keyword::Get: case Keyword::Set: if(this->flags & UNDER_PROTOCOL) { // variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-keyword-block //no code block for getter/setter for protocol std::pair<CodeBlockPtr, CodeBlockPtr> r = parseGetterSetterKeywordBlock(); prop->setGetter(r.first); prop->setSetter(r.second); } else { // variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-block std::pair<CodeBlockPtr, std::pair<std::wstring, CodeBlockPtr> > r = parseGetterSetterBlock(); prop->setGetter(r.first); prop->setSetterName(r.second.first); prop->setSetter(r.second.second); } break; case Keyword::WillSet: case Keyword::DidSet: // variable-declaration → variable-declaration-head variable-name type-annotation initializer opt willSet-didSet-block parseWillSetDidSetBlock(prop); break; default: // variable-declaration → variable-declaration-head variable-name type-annotation code-block CodeBlockPtr getter = nodeFactory->createCodeBlock(token.state); prop->setGetter(getter); do { StatementPtr st = parseStatement(); getter->addStatement(st); }while(!predicate(L"}")); break; } } expect(L"}"); return prop; }
void Interface:: inherits (IdentifierPtr const& id) { if (ctx.trace ()) cerr << " inherits " << id << endl; Name name (id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); try { try { SemanticGraph::Interface& i ( resolve<SemanticGraph::Interface> (from, name, Flags::defined)); switch (qualifier_) { case Qualifier::abstract: { if (dynamic_cast<AbstractInterface*> (&i)) break; throw WrongType (i.scoped_name ()); } case Qualifier::unconstrained: { if (dynamic_cast<UnconstrainedInterface*> (&i) || dynamic_cast<AbstractInterface*> (&i)) break; throw WrongType (i.scoped_name ()); } default: break; } check_inheritance (now ().inherits_begin (), now ().inherits_end (), i); ctx.tu ().new_edge<Inherits> (now (), i); ctx.tu ().new_edge<Extends> (now (), i); } catch (Resolve const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "invalid inheritance specification" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "no interface with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << id->line () << ": error: " << "incompatible type in inheritance specification" << endl; } catch (NotDefined const& e) { cerr << ctx.file () << ":" << id->line () << ": error: " << "attempt to inherit from forward-declared interface " << e.name () << endl; cerr << ctx.file () << ":" << id->line () << ": error: " << "inheritance from forward-declared interface is illegal" << endl; } catch (AlreadyInherited const& e) { cerr << ctx.file () << ":" << id->line () << ": error: " << "directly inheriting from interface \'" << e.name () << "\' more than once is illegal" << endl; } }
void Operation:: parameter (Direction::Value direction, IdentifierPtr const& type_id, SimpleIdentifierPtr const& name_id) { if (ctx.trace ()) cerr << "parameter " << direction << " " << type_id << " " << name_id << endl; Name name (type_id->lexeme ()); ScopedName from (ctx.scope ().scoped_name ()); struct NotIn : Resolve {}; try { try { if (one_way_ && direction != Direction::in) throw NotIn (); Type& t (resolve<Type> (from, name, Flags::complete)); Parameter* p (0); switch (direction) { case Direction::in: { p = &ctx.tu ().new_node<InParameter> ( ctx.file (), name_id->line (), name_id->lexeme ()); break; } case Direction::out: { p = &ctx.tu ().new_node<OutParameter> ( ctx.file (), name_id->line (), name_id->lexeme ()); break; } case Direction::inout: { p = &ctx.tu ().new_node<InOutParameter> ( ctx.file (), name_id->line (), name_id->lexeme ()); break; } } ctx.tu ().new_edge<Belongs> (*p, t); ctx.tu ().new_edge<Receives> (*op_, *p); } catch (Resolve const&) { cerr << ctx.file () << ":" << type_id->line () << ": error: " << "invalid parameter declaration" << endl; throw; } } catch (NotFound const&) { cerr << ctx.file () << ":" << type_id->line () << ": error: " << "no type with name \'" << name << "\' visible from scope \'" << from << "\'" << endl; } catch (WrongType const&) { cerr << ctx.file () << ":" << type_id->line () << ": error: " << "declaration with name \'" << name << "\' visible from scope \'" << from << "\' is not a type declaration" << endl; cerr << ctx.file () << ":" << type_id->line () << ": error: " << "using non-type as an operation parameter type is " << "illegal" << endl; } catch (NotComplete const& e) { cerr << ctx.file () << ":" << type_id->line () << ": error: " << "type \'" << e.name () << "\' is not complete" << endl; } catch (NotIn const&) { cerr << ctx.file () << ":" << type_id->line () << ": error: " << "parameter of oneway operation should have \'in\' " << "direction" << endl; } }