ParseResult Coalesce::parse(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); auto length = arrayLength(value); if (length < 2) { ctx.error("Expected at least one argument."); return ParseResult(); } optional<type::Type> outputType; if (ctx.getExpected() && *ctx.getExpected() != type::Value) { outputType = ctx.getExpected(); } Coalesce::Args args; args.reserve(length - 1); for (std::size_t i = 1; i < length; i++) { auto parsed = ctx.parse(arrayMember(value, i), i, outputType); if (!parsed) { return parsed; } if (!outputType) { outputType = (*parsed)->getType(); } args.push_back(std::move(*parsed)); } assert(outputType); return ParseResult(std::make_unique<Coalesce>(*outputType, std::move(args))); }
ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { static std::unordered_map<std::string, type::Type> types { {"string", type::String}, {"number", type::Number}, {"boolean", type::Boolean}, {"object", type::Object} }; std::size_t length = arrayLength(value); if (length < 2) { ctx.error("Expected at least one argument."); return ParseResult(); } auto it = types.find(*toString(arrayMember(value, 0))); assert(it != types.end()); std::vector<std::unique_ptr<Expression>> parsed; parsed.reserve(length - 1); for (std::size_t i = 1; i < length; i++) { ParseResult input = ctx.parse(arrayMember(value, i), i, {type::Value}); if (!input) return ParseResult(); parsed.push_back(std::move(*input)); } return ParseResult(std::make_unique<Assertion>(it->second, std::move(parsed))); }
Expr Ast_Select::_parse_in( ParsingContext &context ) const { Expr f_expr = f->parse_in( context ); Vec<Expr> arg_exprs( Rese(), args.size() ); for( Past a : args ) arg_exprs << a->parse_in( context ); return context.apply( context.get_attr( f_expr, "select" ), args.size() - names.size(), arg_exprs.ptr(), names.size(), names.ptr(), arg_exprs.end() - names.size() ); }
static ParseResult create(type::Type outputType, std::unique_ptr<Expression>input, std::vector<std::pair<std::vector<InputType>, std::unique_ptr<Expression>>> branches, std::unique_ptr<Expression> otherwise, ParsingContext& ctx) { typename Match<T>::Branches typedBranches; std::size_t index = 2; typedBranches.reserve(branches.size()); for (std::pair<std::vector<InputType>, std::unique_ptr<Expression>>& pair : branches) { std::shared_ptr<Expression> result = std::move(pair.second); for (const InputType& label : pair.first) { const auto& typedLabel = label.template get<T>(); if (typedBranches.find(typedLabel) != typedBranches.end()) { ctx.error("Branch labels must be unique.", index); return ParseResult(); } typedBranches.emplace(typedLabel, result); } index += 2; } return ParseResult(std::make_unique<Match<T>>( outputType, std::move(input), std::move(typedBranches), std::move(otherwise) )); }
static void DrawTriMeshMarker( Metal::DeviceContext& devContext, ParsingContext& parserContext, const VisGeoBox& visBox, const ResolvedShader& shader, const RetainedEntity& obj, EntityInterface::RetainedEntities& objs) { static auto IndexListHash = ParameterBox::MakeParameterNameHash("IndexList"); if (!obj._properties.GetParameter(Parameters::Visible, true) || !GetShowMarker(obj)) return; // we need an index list with at least 3 indices (to make at least one triangle) auto indexListType = obj._properties.GetParameterType(IndexListHash); if (indexListType._type == ImpliedTyping::TypeCat::Void || indexListType._arrayCount < 3) return; auto ibData = std::make_unique<unsigned[]>(indexListType._arrayCount); bool success = obj._properties.GetParameter( IndexListHash, ibData.get(), ImpliedTyping::TypeDesc(ImpliedTyping::TypeCat::UInt32, indexListType._arrayCount)); if (!success) return; const auto& chld = obj._children; if (!chld.size()) return; auto vbData = std::make_unique<Float3[]>(chld.size()); for (size_t c=0; c<chld.size(); ++c) { const auto* e = objs.GetEntity(obj._doc, chld[c]); if (e) { vbData[c] = ExtractTranslation(GetTransform(*e)); } else { vbData[c] = Zero<Float3>(); } } const auto& cbLayout = ::Assets::GetAssetDep<Techniques::PredefinedCBLayout>( "game/xleres/BasicMaterialConstants.txt"); shader.Apply(devContext, parserContext, { MakeLocalTransformPacket( GetTransform(obj), ExtractTranslation(parserContext.GetProjectionDesc()._cameraToWorld)), cbLayout.BuildCBDataAsPkt(ParameterBox()) }); devContext.Bind(Techniques::CommonResources()._blendAdditive); devContext.Bind(Techniques::CommonResources()._dssReadOnly); devContext.Bind(Techniques::CommonResources()._cullDisable); Metal::VertexBuffer vb(vbData.get(), sizeof(Float3)*chld.size()); Metal::IndexBuffer ib(ibData.get(), sizeof(unsigned)*indexListType._arrayCount); devContext.Bind(MakeResourceList(vb), sizeof(Float3), 0); devContext.Bind(ib, Metal::NativeFormat::R32_UINT); devContext.Bind(Metal::Topology::TriangleList); devContext.DrawIndexed(indexListType._arrayCount); }
ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ctx) { std::size_t argsLength = arrayLength(value); if (argsLength < 3) { ctx.error("Expected at least two arguments."); return ParseResult(); } if ((argsLength - 1) % 2 != 0) { ctx.error("Expected an even number of arguments."); return ParseResult(); } std::vector<FormatExpressionSection> sections; for (std::size_t i = 1; i < argsLength - 1; i += 2) { auto textArg = arrayMember(value, i); ParseResult text = ctx.parse(textArg, 1, {type::Value}); if (!text) { return ParseResult(); } auto options = arrayMember(value, i + 1); if (!isObject(options)) { ctx.error("Format options argument must be an object."); return ParseResult(); } const optional<Convertible> fontScaleOption = objectMember(options, kFormattedSectionFontScale); ParseResult fontScale; if (fontScaleOption) { fontScale = ctx.parse(*fontScaleOption, 1, {type::Number}); if (!fontScale) { return ParseResult(); } } const optional<Convertible> textFontOption = objectMember(options, kFormattedSectionTextFont); ParseResult textFont; if (textFontOption) { textFont = ctx.parse(*textFontOption, 1, {type::Array(type::String)}); if (!textFont) { return ParseResult(); } } const optional<Convertible> textColorOption = objectMember(options, kFormattedSectionTextColor); ParseResult textColor; if (textColorOption) { textColor = ctx.parse(*textColorOption, 1, {type::Color}); if (!textColor) { return ParseResult(); } } sections.emplace_back(std::move(*text), std::move(fontScale), std::move(textFont), std::move(textColor)); } return ParseResult(std::make_unique<FormatExpression>(std::move(sections))); }
ParseResult CollatorExpression::parse(const Convertible& value, ParsingContext& ctx) { if (arrayLength(value) != 2) { ctx.error("Expected one argument."); return ParseResult(); } auto options = arrayMember(value, 1); if (!isObject(options)) { ctx.error("Collator options argument must be an object."); return ParseResult(); } const optional<Convertible> caseSensitiveOption = objectMember(options, "case-sensitive"); ParseResult caseSensitive; if (caseSensitiveOption) { caseSensitive = ctx.parse(*caseSensitiveOption, 1, {type::Boolean}); } else { caseSensitive = { std::make_unique<Literal>(false) }; } if (!caseSensitive) { return ParseResult(); } const optional<Convertible> diacriticSensitiveOption = objectMember(options, "diacritic-sensitive"); ParseResult diacriticSensitive; if (diacriticSensitiveOption) { diacriticSensitive = ctx.parse(*diacriticSensitiveOption, 1, {type::Boolean}); } else { diacriticSensitive = { std::make_unique<Literal>(false) }; } if (!diacriticSensitive) { return ParseResult(); } const optional<Convertible> localeOption = objectMember(options, "locale"); ParseResult locale; if (localeOption) { locale = ctx.parse(*localeOption, 1, {type::String}); if (!locale) { return ParseResult(); } } return ParseResult(std::make_unique<CollatorExpression>(std::move(*caseSensitive), std::move(*diacriticSensitive), std::move(locale))); }
ParseResult Var::parse(const Convertible& value_, ParsingContext& ctx) { assert(isArray(value_)); if (arrayLength(value_) != 2 || !toString(arrayMember(value_, 1))) { ctx.error("'var' expression requires exactly one string literal argument."); return ParseResult(); } std::string name_ = *toString(arrayMember(value_, 1)); optional<std::shared_ptr<Expression>> bindingValue = ctx.getBinding(name_); if (!bindingValue) { ctx.error(R"(Unknown variable ")" + name_ + R"(". Make sure ")" + name_ + R"(" has been bound in an enclosing "let" expression before using it.)", 1); return ParseResult(); } return ParseResult(std::make_unique<Var>(name_, std::move(*bindingValue))); }
ParseResult At::parse(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); std::size_t length = arrayLength(value); if (length != 3) { ctx.error("Expected 2 arguments, but found " + util::toString(length - 1) + " instead."); return ParseResult(); } ParseResult index = ctx.parse(arrayMember(value, 1), 1, {type::Number}); type::Type inputType = type::Array(ctx.getExpected() ? *ctx.getExpected() : type::Value); ParseResult input = ctx.parse(arrayMember(value, 2), 2, {inputType}); if (!index || !input) return ParseResult(); return ParseResult(std::make_unique<At>(std::move(*index), std::move(*input))); }
Expr Ast_Def::_parse_in( ParsingContext &context ) const { std::set<String> res; if ( context.parent ) { std::set<String> avail; avail.insert( name ); get_potentially_needed_ext_vars( res, avail ); } // Def *c = new Def( this ); // SI64 ptr = SI64( ST( c ) ); Expr out = room( cst( ip->type_Def, 64, &ptr ) ); out->flags |= Inst::SURDEF; if ( stat ) out->flags |= Inst::STATIC; return context.reg_var( name, out, true ); }
static void DrawObject( Metal::DeviceContext& devContext, ParsingContext& parserContext, const VisGeoBox& visBox, const ResolvedShader& shader, const RetainedEntity& obj) { if (!obj._properties.GetParameter(Parameters::Visible, true) || !GetShowMarker(obj)) return; const auto& cbLayout = ::Assets::GetAssetDep<Techniques::PredefinedCBLayout>( "game/xleres/BasicMaterialConstants.txt"); shader.Apply(devContext, parserContext, { MakeLocalTransformPacket( GetTransform(obj), ExtractTranslation(parserContext.GetProjectionDesc()._cameraToWorld)), cbLayout.BuildCBDataAsPkt(ParameterBox()) }); devContext.Bind(MakeResourceList(visBox._cubeVB), visBox._cubeVBStride, 0); devContext.Draw(visBox._cubeVBCount); }
Expr Ast_Class::_parse_in( ParsingContext &context ) const { std::set<String> res; if ( context.parent ) { std::set<String> avail; avail.insert( name ); get_potentially_needed_ext_vars( res, avail ); } // Class *c = 0; #define DECL_BT( T ) if ( name == #T ) { c = ip->class_##T; c->ast_item = this; } #include "../Ssa/DeclBaseClass.h" #include "../Ssa/DeclParmClass.h" #undef DECL_BT if ( not c ) c = new Class( this ); // SI64 ptr = SI64( ST( c ) ); Expr val = cst( ip->type_Class, 64, &ptr ); Expr out = room( val ); out->flags |= Inst::SURDEF; return context.reg_var( name, out, true ); }
ParseResult Let::parse(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); std::size_t length = arrayLength(value); if (length < 4) { ctx.error("Expected at least 3 arguments, but found " + util::toString(length - 1) + " instead."); return ParseResult(); } std::map<std::string, std::shared_ptr<Expression>> bindings_; for(std::size_t i = 1; i < length - 1; i += 2) { optional<std::string> name = toString(arrayMember(value, i)); if (!name) { ctx.error("Expected string, but found " + getJSONType(arrayMember(value, i)) + " instead.", i); return ParseResult(); } bool isValidName = std::all_of(name->begin(), name->end(), [](unsigned char c) { return ::isalnum(c) || c == '_'; }); if (!isValidName) { ctx.error("Variable names must contain only alphanumeric characters or '_'.", 1); return ParseResult(); } ParseResult bindingValue = ctx.parse(arrayMember(value, i + 1), i + 1); if (!bindingValue) { return ParseResult(); } bindings_.emplace(*name, std::move(*bindingValue)); } ParseResult result_ = ctx.parse(arrayMember(value, length - 1), length - 1, ctx.getExpected(), bindings_); if (!result_) { return ParseResult(); } return ParseResult(std::make_unique<Let>(std::move(bindings_), std::move(*result_))); }
Expr Ast_Import::_parse_in( ParsingContext &context ) const { return context.ret_error( "TODO: _parse_in", false, __FILE__, __LINE__ ); }
Expr Ast_Variable::_parse_in( ParsingContext &context ) const { return context.get_var( str ); }
optional<InputType> parseInputValue(const Convertible& input, ParsingContext& parentContext, std::size_t index, optional<type::Type>& inputType) { using namespace mbgl::style::conversion; optional<InputType> result; optional<type::Type> type; auto value = toValue(input); if (value) { value->match( [&] (uint64_t n) { if (!Value::isSafeInteger(n)) { parentContext.error("Branch labels must be integers no larger than " + util::toString(Value::maxSafeInteger()) + ".", index); } else { type = {type::Number}; result = optional<InputType>{static_cast<int64_t>(n)}; } }, [&] (int64_t n) { if (!Value::isSafeInteger(n)) { parentContext.error("Branch labels must be integers no larger than " + util::toString(Value::maxSafeInteger()) + ".", index); } else { type = {type::Number}; result = optional<InputType>{n}; } }, [&] (double n) { if (!Value::isSafeInteger(n)) { parentContext.error("Branch labels must be integers no larger than " + util::toString(Value::maxSafeInteger()) + ".", index); } else if (n != std::floor(n)) { parentContext.error("Numeric branch labels must be integer values.", index); } else { type = {type::Number}; result = optional<InputType>{static_cast<int64_t>(n)}; } }, [&] (const std::string& s) { type = {type::String}; result = {s}; }, [&] (const auto&) { parentContext.error("Branch labels must be numbers or strings.", index); } ); } else { parentContext.error("Branch labels must be numbers or strings.", index); } if (!type) { return result; } if (!inputType) { inputType = type; } else { optional<std::string> err = type::checkSubtype(*inputType, *type); if (err) { parentContext.error(*err, index); return optional<InputType>(); } } return result; }
Expr Ast_While::_parse_in( ParsingContext &context ) const { // watch modified variables IpSnapshot nsv( ip->ip_snapshot ); // we repeat until there are no external modified values int ne = ip->error_list.size(); std::map<Expr,Expr> unknowns; for( unsigned old_nsv_size = 0, cpt = 0; ; old_nsv_size = nsv.rooms.size(), ++cpt ) { if ( cpt == 20 ) return context.ret_error( "infinite loop during while parsing" ); ParsingContext wh_scope( &context, 0, "while_" + to_string( ok ) ); wh_scope.cont = true; ok->parse_in( wh_scope ); if ( ne != ip->error_list.size() ) return Expr(); // if no new modified variables if ( old_nsv_size == nsv.rooms.size() ) break; // replace each modified variable to a new unknown variables // (to avoid simplifications during the next round) for( std::pair<Inst *const,Expr> &it : nsv.rooms ) { Expr unk = unknown_inst( it.second->type(), cpt ); unknowns[ it.first ] = unk; const_cast<Inst *>( it.first )->set( unk, true ); } nsv.undo_parsing_contexts(); } // corr table (output number -> input number) // -> find if Unknown inst are used to compute the outputs ++Inst::cur_op_id; for( std::pair<Inst *const,Expr> &it : nsv.rooms ) const_cast<Inst *>( it.first )->get( context.cond )->mark_children(); int cpt = 0; Vec<int> corr; Vec<Type *> inp_types; for( std::pair<Inst *const,Expr> &it : nsv.rooms ) { if ( unknowns[ it.first ]->op_id == Inst::cur_op_id ) { corr << cpt++; inp_types << it.second->type(); } else corr << -1; } // prepare a while inp (for initial values of variables modified in the loop) Expr winp = while_inp( inp_types ); // set winp[...] as initial values of modified variables cpt = 0; for( std::pair<Inst *const,Expr> &it : nsv.rooms ) { int num_inp = corr[ cpt++ ]; if ( num_inp >= 0 ) const_cast<Inst *>( it.first )->set( get_nout( winp, num_inp ), true ); else const_cast<Inst *>( it.first )->set( it.second, true ); } nsv.undo_parsing_contexts(); // relaunch the while inst ParsingContext wh_scope( &context, 0, "while_" + to_string( ok ) ); wh_scope.cont = true; ok->parse_in( wh_scope ); if ( wh_scope.cont->always( false ) ) { ip->ip_snapshot = nsv.prev; } else { // make the while instruction Vec<Expr> out_exprs; for( std::pair<Inst *const,Expr> &it : nsv.rooms ) out_exprs << const_cast<Inst *>( it.first )->get( context.cond ); Expr wout = while_out( out_exprs, wh_scope.cont ); cpt = 0; Vec<Expr> inp_exprs; for( std::pair<Inst *const,Expr> &it : nsv.rooms ) if ( corr[ cpt++ ] >= 0 ) inp_exprs << it.second->simplified( context.cond ); Expr wins = while_inst( inp_exprs, winp, wout, corr ); ip->ip_snapshot = nsv.prev; // replace changed variable by while_inst outputs cpt = 0; for( std::pair<Inst *const,Expr> &it : nsv.rooms ) const_cast<Inst *>( it.first )->set( get_nout( wins, cpt++ ), context.cond ); } // break(s) to transmit ? for( ParsingContext::RemBreak rb : wh_scope.rem_breaks ) context.BREAK( rb.count, rb.cond ); return ip->void_var(); }
ParseResult parseMatch(const Convertible& value, ParsingContext& ctx) { assert(isArray(value)); auto length = arrayLength(value); if (length < 5) { ctx.error( "Expected at least 4 arguments, but found only " + util::toString(length - 1) + "." ); return ParseResult(); } // Expect odd-length array: ["match", input, 2 * (n pairs)..., otherwise] if (length % 2 != 1) { ctx.error("Expected an even number of arguments."); return ParseResult(); } optional<type::Type> inputType; optional<type::Type> outputType; if (ctx.getExpected() && *ctx.getExpected() != type::Value) { outputType = ctx.getExpected(); } std::vector<std::pair<std::vector<InputType>, std::unique_ptr<Expression>>> branches; branches.reserve((length - 3) / 2); for (size_t i = 2; i + 1 < length; i += 2) { const auto& label = arrayMember(value, i); std::vector<InputType> labels; // Match pair inputs are provided as either a literal value or a // raw JSON array of string / number / boolean values. if (isArray(label)) { auto groupLength = arrayLength(label); if (groupLength == 0) { ctx.error("Expected at least one branch label.", i); return ParseResult(); } labels.reserve(groupLength); for (size_t j = 0; j < groupLength; j++) { const optional<InputType> inputValue = parseInputValue(arrayMember(label, j), ctx, i, inputType); if (!inputValue) { return ParseResult(); } labels.push_back(*inputValue); } } else { const optional<InputType> inputValue = parseInputValue(label, ctx, i, inputType); if (!inputValue) { return ParseResult(); } labels.push_back(*inputValue); } ParseResult output = ctx.parse(arrayMember(value, i + 1), i + 1, outputType); if (!output) { return ParseResult(); } if (!outputType) { outputType = (*output)->getType(); } branches.emplace_back(std::move(labels), std::move(*output)); } auto input = ctx.parse(arrayMember(value, 1), 1, {type::Value}); if (!input) { return ParseResult(); } auto otherwise = ctx.parse(arrayMember(value, length - 1), length - 1, outputType); if (!otherwise) { return ParseResult(); } assert(inputType && outputType); optional<std::string> err; if ((*input)->getType() != type::Value && (err = type::checkSubtype(*inputType, (*input)->getType()))) { ctx.error(*err, 1); return ParseResult(); } return inputType->match( [&](const type::NumberType&) { return create<int64_t>(*outputType, std::move(*input), std::move(branches), std::move(*otherwise), ctx); }, [&](const type::StringType&) { return create<std::string>(*outputType, std::move(*input), std::move(branches), std::move(*otherwise), ctx); }, [&](const auto&) { // unreachable: inputType is set by parseInputValue(), which only // accepts string and (integer) numeric values. assert(false); return ParseResult(); } ); }
Expr Ast_GetAttr::_parse_in( ParsingContext &context ) const { Expr self = obj->parse_in( context ); if ( ptr or ask or ddo ) TODO; return context.get_attr( self, name ); }