Example #1
0
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)));
}
Example #3
0
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() );
}
Example #4
0
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)
    ));
}
Example #5
0
    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)));
}
Example #8
0
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)));
}
Example #9
0
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)));

}
Example #10
0
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 );
}
Example #11
0
    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);
    }
Example #12
0
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 );
}
Example #13
0
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_)));
}
Example #14
0
Expr Ast_Import::_parse_in( ParsingContext &context ) const {
    return context.ret_error( "TODO: _parse_in", false, __FILE__, __LINE__ );
}
Example #15
0
Expr Ast_Variable::_parse_in( ParsingContext &context ) const {
    return context.get_var( str );
}
Example #16
0
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;
}
Example #17
0
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();
}
Example #18
0
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();
        }
    );
}
Example #19
0
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 );
}