| /* |
| * Copyright 2020 Google LLC. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "src/sksl/SkSLRehydrator.h" |
| |
| #include "include/private/SkSLModifiers.h" |
| #include "include/private/SkSLProgramElement.h" |
| #include "include/private/SkSLProgramKind.h" |
| #include "include/private/SkSLStatement.h" |
| #include "include/private/SkSLSymbol.h" |
| #include "include/private/SkTArray.h" |
| #include "include/sksl/DSLCore.h" |
| #include "include/sksl/SkSLOperator.h" |
| #include "include/sksl/SkSLPosition.h" |
| #include "include/sksl/SkSLVersion.h" |
| #include "src/sksl/SkSLAnalysis.h" |
| #include "src/sksl/SkSLCompiler.h" |
| #include "src/sksl/SkSLModifiersPool.h" |
| #include "src/sksl/SkSLParsedModule.h" |
| #include "src/sksl/SkSLPool.h" |
| #include "src/sksl/SkSLProgramSettings.h" |
| #include "src/sksl/SkSLThreadContext.h" |
| #include "src/sksl/ir/SkSLBinaryExpression.h" |
| #include "src/sksl/ir/SkSLBlock.h" |
| #include "src/sksl/ir/SkSLBreakStatement.h" |
| #include "src/sksl/ir/SkSLConstructorArray.h" |
| #include "src/sksl/ir/SkSLConstructorArrayCast.h" |
| #include "src/sksl/ir/SkSLConstructorCompound.h" |
| #include "src/sksl/ir/SkSLConstructorCompoundCast.h" |
| #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h" |
| #include "src/sksl/ir/SkSLConstructorMatrixResize.h" |
| #include "src/sksl/ir/SkSLConstructorScalarCast.h" |
| #include "src/sksl/ir/SkSLConstructorSplat.h" |
| #include "src/sksl/ir/SkSLConstructorStruct.h" |
| #include "src/sksl/ir/SkSLContinueStatement.h" |
| #include "src/sksl/ir/SkSLDiscardStatement.h" |
| #include "src/sksl/ir/SkSLDoStatement.h" |
| #include "src/sksl/ir/SkSLExpression.h" |
| #include "src/sksl/ir/SkSLExpressionStatement.h" |
| #include "src/sksl/ir/SkSLField.h" |
| #include "src/sksl/ir/SkSLFieldAccess.h" |
| #include "src/sksl/ir/SkSLForStatement.h" |
| #include "src/sksl/ir/SkSLFunctionCall.h" |
| #include "src/sksl/ir/SkSLFunctionDeclaration.h" |
| #include "src/sksl/ir/SkSLFunctionDefinition.h" |
| #include "src/sksl/ir/SkSLFunctionPrototype.h" |
| #include "src/sksl/ir/SkSLIfStatement.h" |
| #include "src/sksl/ir/SkSLIndexExpression.h" |
| #include "src/sksl/ir/SkSLInterfaceBlock.h" |
| #include "src/sksl/ir/SkSLLiteral.h" |
| #include "src/sksl/ir/SkSLNop.h" |
| #include "src/sksl/ir/SkSLPostfixExpression.h" |
| #include "src/sksl/ir/SkSLPrefixExpression.h" |
| #include "src/sksl/ir/SkSLProgram.h" |
| #include "src/sksl/ir/SkSLReturnStatement.h" |
| #include "src/sksl/ir/SkSLSetting.h" |
| #include "src/sksl/ir/SkSLStructDefinition.h" |
| #include "src/sksl/ir/SkSLSwitchCase.h" |
| #include "src/sksl/ir/SkSLSwitchStatement.h" |
| #include "src/sksl/ir/SkSLSwizzle.h" |
| #include "src/sksl/ir/SkSLSymbolTable.h" |
| #include "src/sksl/ir/SkSLTernaryExpression.h" |
| #include "src/sksl/ir/SkSLType.h" |
| #include "src/sksl/ir/SkSLUnresolvedFunction.h" |
| #include "src/sksl/ir/SkSLVarDeclarations.h" |
| #include "src/sksl/ir/SkSLVariable.h" |
| #include "src/sksl/ir/SkSLVariableReference.h" |
| |
| #include <stdio.h> |
| #include <memory> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| namespace SkSL { |
| |
| class AutoRehydratorSymbolTable { |
| public: |
| AutoRehydratorSymbolTable(Rehydrator* rehydrator) |
| : fRehydrator(rehydrator) |
| , fOldSymbols(fRehydrator->fSymbolTable) { |
| std::shared_ptr<SymbolTable> symbols = fRehydrator->symbolTable(); |
| if (symbols) { |
| fRehydrator->fSymbolTable = std::move(symbols); |
| } |
| } |
| |
| ~AutoRehydratorSymbolTable() { |
| fRehydrator->fSymbolTable = std::move(fOldSymbols); |
| } |
| |
| private: |
| Rehydrator* fRehydrator; |
| std::shared_ptr<SymbolTable> fOldSymbols; |
| }; |
| |
| Rehydrator::Rehydrator(Compiler& compiler, const uint8_t* src, size_t length, |
| std::shared_ptr<SymbolTable> symbols) |
| : fCompiler(compiler) |
| , fSymbolTable(symbols ? std::move(symbols) : compiler.makeGLSLRootSymbolTable()) |
| SkDEBUGCODE(, fEnd(src + length)) { |
| SkASSERT(fSymbolTable); |
| SkASSERT(fSymbolTable->isBuiltin()); |
| fIP = src; |
| [[maybe_unused]] uint16_t version = this->readU16(); |
| SkASSERTF(version == kVersion, "Dehydrated file is an unsupported version (current version is " |
| "%d, found version %d)", kVersion, version); |
| fStringStart = fIP; |
| // skip over string data |
| fIP += this->readU16(); |
| } |
| |
| #ifdef SK_DEBUG |
| Rehydrator::~Rehydrator() { |
| // ensure that we have read the expected number of bytes |
| SkASSERT(fIP == fEnd); |
| } |
| #endif |
| |
| Context& Rehydrator::context() const { |
| return fCompiler.context(); |
| } |
| |
| Layout Rehydrator::layout() { |
| switch (this->readU8()) { |
| case kBuiltinLayout_Command: { |
| Layout result; |
| result.fBuiltin = this->readS16(); |
| return result; |
| } |
| case kDefaultLayout_Command: |
| return Layout(); |
| case kLayout_Command: { |
| int flags = this->readU32(); |
| int location = this->readS8(); |
| int offset = this->readS16(); |
| int binding = this->readS16(); |
| int index = this->readS8(); |
| int set = this->readS8(); |
| int builtin = this->readS16(); |
| int inputAttachmentIndex = this->readS8(); |
| return Layout( |
| flags, location, offset, binding, index, set, builtin, inputAttachmentIndex); |
| } |
| default: |
| SkASSERT(false); |
| return Layout(); |
| } |
| } |
| |
| Modifiers Rehydrator::modifiers() { |
| switch (this->readU8()) { |
| case kDefaultModifiers_Command: |
| return Modifiers(); |
| case kModifiers8Bit_Command: { |
| Layout l = this->layout(); |
| int flags = this->readU8(); |
| return Modifiers(l, flags); |
| } |
| case kModifiers_Command: { |
| Layout l = this->layout(); |
| int flags = this->readS32(); |
| return Modifiers(l, flags); |
| } |
| default: |
| SkASSERT(false); |
| return Modifiers(); |
| } |
| } |
| |
| const Symbol* Rehydrator::symbol() { |
| int kind = this->readU8(); |
| switch (kind) { |
| case kArrayType_Command: { |
| uint16_t id = this->readU16(); |
| const Type* componentType = this->type(); |
| int8_t count = this->readS8(); |
| const std::string* arrayName = |
| fSymbolTable->takeOwnershipOfString(componentType->getArrayName(count)); |
| const Type* result = fSymbolTable->takeOwnershipOfSymbol( |
| Type::MakeArrayType(*arrayName, *componentType, count)); |
| this->addSymbol(id, result); |
| return result; |
| } |
| case kFunctionDeclaration_Command: { |
| uint16_t id = this->readU16(); |
| Modifiers modifiers = this->modifiers(); |
| std::string_view name = this->readString(); |
| int parameterCount = this->readU8(); |
| std::vector<const Variable*> parameters; |
| parameters.reserve(parameterCount); |
| for (int i = 0; i < parameterCount; ++i) { |
| parameters.push_back(this->symbolRef<Variable>()); |
| } |
| const Type* returnType = this->type(); |
| const FunctionDeclaration* result = |
| fSymbolTable->takeOwnershipOfSymbol(std::make_unique<FunctionDeclaration>( |
| Position(), |
| this->modifiersPool().add(modifiers), |
| name, |
| std::move(parameters), |
| returnType, |
| fSymbolTable->isBuiltin())); |
| this->addSymbol(id, result); |
| return result; |
| } |
| case kField_Command: { |
| const Variable* owner = this->symbolRef<Variable>(); |
| uint8_t index = this->readU8(); |
| const Field* result = fSymbolTable->takeOwnershipOfSymbol( |
| std::make_unique<Field>(Position(), owner, index)); |
| return result; |
| } |
| case kStructType_Command: { |
| uint16_t id = this->readU16(); |
| std::string name(this->readString()); |
| uint8_t fieldCount = this->readU8(); |
| std::vector<Type::Field> fields; |
| fields.reserve(fieldCount); |
| for (int i = 0; i < fieldCount; ++i) { |
| Modifiers m = this->modifiers(); |
| std::string_view fieldName = this->readString(); |
| const Type* type = this->type(); |
| fields.emplace_back(Position(), m, fieldName, type); |
| } |
| bool interfaceBlock = this->readU8(); |
| std::string_view nameChars(*fSymbolTable->takeOwnershipOfString(std::move(name))); |
| const Type* result = fSymbolTable->takeOwnershipOfSymbol(Type::MakeStructType( |
| Position(), nameChars, std::move(fields), interfaceBlock)); |
| this->addSymbol(id, result); |
| return result; |
| } |
| case kSymbolRef_Command: { |
| return this->possiblyBuiltinSymbolRef(); |
| } |
| case kUnresolvedFunction_Command: { |
| uint16_t id = this->readU16(); |
| int length = this->readU8(); |
| std::vector<const FunctionDeclaration*> functions; |
| functions.reserve(length); |
| for (int i = 0; i < length; ++i) { |
| const Symbol* f = this->symbol(); |
| SkASSERT(f && f->kind() == Symbol::Kind::kFunctionDeclaration); |
| functions.push_back((const FunctionDeclaration*) f); |
| } |
| const UnresolvedFunction* result = fSymbolTable->takeOwnershipOfSymbol( |
| std::make_unique<UnresolvedFunction>(std::move(functions))); |
| this->addSymbol(id, result); |
| return result; |
| } |
| case kVariable_Command: { |
| uint16_t id = this->readU16(); |
| const Modifiers* m = this->modifiersPool().add(this->modifiers()); |
| std::string_view name = this->readString(); |
| const Type* type = this->type(); |
| Variable::Storage storage = (Variable::Storage) this->readU8(); |
| const Variable* result = fSymbolTable->takeOwnershipOfSymbol(std::make_unique<Variable>( |
| /*pos=*/Position(), /*modifiersPosition=*/Position(), m, name, type, |
| fSymbolTable->isBuiltin(), storage)); |
| this->addSymbol(id, result); |
| return result; |
| } |
| default: |
| printf("unsupported symbol %d\n", kind); |
| SkASSERT(false); |
| return nullptr; |
| } |
| } |
| |
| const Type* Rehydrator::type() { |
| const Symbol* result = this->symbol(); |
| SkASSERT(result->kind() == Symbol::Kind::kType); |
| return (const Type*) result; |
| } |
| |
| std::unique_ptr<Program> Rehydrator::program() { |
| [[maybe_unused]] uint8_t command = this->readU8(); |
| SkASSERT(command == kProgram_Command); |
| |
| // Initialize the temporary config used to generate the complete program. We explicitly avoid |
| // enforcing ES2 restrictions when rehydrating a program, which we assume to be already |
| // well-formed when dehydrated. |
| auto config = std::make_unique<ProgramConfig>(); |
| config->fKind = (ProgramKind)this->readU8(); |
| config->fRequiredSkSLVersion = (SkSL::Version)this->readU8(); |
| config->fSettings.fEnforceES2Restrictions = false; |
| |
| Context& context = this->context(); |
| ProgramConfig* oldConfig = context.fConfig; |
| ModifiersPool* oldModifiersPool = context.fModifiersPool; |
| context.fConfig = config.get(); |
| fSymbolTable = fCompiler.moduleForProgramKind(config->fKind).fSymbols; |
| dsl::Start(&fCompiler, config->fKind, config->fSettings); |
| auto modifiers = std::make_unique<ModifiersPool>(); |
| context.fModifiersPool = modifiers.get(); |
| this->symbolTable(); |
| std::vector<std::unique_ptr<ProgramElement>> elements = this->elements(); |
| context.fConfig = oldConfig; |
| context.fModifiersPool = oldModifiersPool; |
| Program::Inputs inputs; |
| inputs.fUseFlipRTUniform = this->readU8(); |
| std::unique_ptr<Pool> pool = std::move(ThreadContext::MemoryPool()); |
| pool->detachFromThread(); |
| std::unique_ptr<Program> result = std::make_unique<Program>(nullptr, std::move(config), |
| fCompiler.fContext, std::move(elements), |
| /*sharedElements=*/std::vector<const ProgramElement*>(), std::move(modifiers), |
| fSymbolTable, std::move(pool), inputs); |
| fSymbolTable = fSymbolTable->fParent; |
| dsl::End(); |
| return result; |
| } |
| |
| std::vector<std::unique_ptr<ProgramElement>> Rehydrator::elements() { |
| SkDEBUGCODE(uint8_t command = )this->readU8(); |
| SkASSERT(command == kElements_Command); |
| std::vector<std::unique_ptr<ProgramElement>> result; |
| while (std::unique_ptr<ProgramElement> elem = this->element()) { |
| result.push_back(std::move(elem)); |
| } |
| return result; |
| } |
| |
| std::unique_ptr<ProgramElement> Rehydrator::element() { |
| int kind = this->readU8(); |
| switch (kind) { |
| case Rehydrator::kFunctionDefinition_Command: { |
| const FunctionDeclaration* decl = this->symbolRef<FunctionDeclaration>(); |
| std::unique_ptr<Statement> body = this->statement(); |
| auto result = FunctionDefinition::Convert(this->context(), Position(), *decl, |
| std::move(body), fSymbolTable->isBuiltin()); |
| decl->setDefinition(result.get()); |
| return std::move(result); |
| } |
| case Rehydrator::kFunctionPrototype_Command: { |
| const FunctionDeclaration* decl = this->symbolRef<FunctionDeclaration>(); |
| // since we skip over builtin prototypes when dehydrating, we know that this |
| // builtin=false |
| return std::make_unique<FunctionPrototype>(Position(), decl, /*builtin=*/false); |
| } |
| case Rehydrator::kGlobalVar_Command: { |
| std::unique_ptr<Statement> decl = this->statement(); |
| return std::make_unique<GlobalVarDeclaration>(std::move(decl)); |
| } |
| case Rehydrator::kInterfaceBlock_Command: { |
| const Symbol* var = this->symbol(); |
| SkASSERT(var && var->is<Variable>()); |
| std::string_view typeName = this->readString(); |
| std::string_view instanceName = this->readString(); |
| int arraySize = this->readU8(); |
| return std::make_unique<InterfaceBlock>(Position(), var->as<Variable>(), typeName, |
| instanceName, arraySize, nullptr); |
| } |
| case Rehydrator::kStructDefinition_Command: { |
| const Symbol* type = this->symbol(); |
| SkASSERT(type && type->is<Type>()); |
| return std::make_unique<StructDefinition>(Position(), type->as<Type>()); |
| } |
| case Rehydrator::kSharedFunction_Command: { |
| int count = this->readU8(); |
| for (int i = 0; i < count; ++i) { |
| [[maybe_unused]] const Symbol* param = this->symbol(); |
| SkASSERT(param->is<Variable>()); |
| } |
| [[maybe_unused]] const Symbol* decl = this->symbol(); |
| SkASSERT(decl->is<FunctionDeclaration>()); |
| std::unique_ptr<ProgramElement> result = this->element(); |
| SkASSERT(result->is<FunctionDefinition>()); |
| return result; |
| } |
| case Rehydrator::kElementsComplete_Command: |
| return nullptr; |
| default: |
| SkDEBUGFAILF("unsupported element %d\n", kind); |
| return nullptr; |
| } |
| } |
| |
| std::unique_ptr<Statement> Rehydrator::statement() { |
| int kind = this->readU8(); |
| switch (kind) { |
| case Rehydrator::kBlock_Command: { |
| AutoRehydratorSymbolTable symbols(this); |
| int count = this->readU8(); |
| StatementArray statements; |
| statements.reserve_back(count); |
| for (int i = 0; i < count; ++i) { |
| statements.push_back(this->statement()); |
| } |
| Block::Kind blockKind = (Block::Kind)this->readU8(); |
| return Block::Make(Position(), std::move(statements), blockKind, fSymbolTable); |
| } |
| case Rehydrator::kBreak_Command: |
| return BreakStatement::Make(Position()); |
| case Rehydrator::kContinue_Command: |
| return ContinueStatement::Make(Position()); |
| case Rehydrator::kDiscard_Command: |
| return DiscardStatement::Make(Position()); |
| case Rehydrator::kDo_Command: { |
| std::unique_ptr<Statement> stmt = this->statement(); |
| std::unique_ptr<Expression> expr = this->expression(); |
| return DoStatement::Make(this->context(), Position(), std::move(stmt), std::move(expr)); |
| } |
| case Rehydrator::kExpressionStatement_Command: { |
| std::unique_ptr<Expression> expr = this->expression(); |
| return ExpressionStatement::Make(this->context(), std::move(expr)); |
| } |
| case Rehydrator::kFor_Command: { |
| AutoRehydratorSymbolTable symbols(this); |
| std::unique_ptr<Statement> initializer = this->statement(); |
| std::unique_ptr<Expression> test = this->expression(); |
| std::unique_ptr<Expression> next = this->expression(); |
| std::unique_ptr<Statement> body = this->statement(); |
| std::unique_ptr<LoopUnrollInfo> unrollInfo = |
| Analysis::GetLoopUnrollInfo(Position(), ForLoopPositions{}, |
| initializer.get(), test.get(), next.get(), body.get(), /*errors=*/nullptr); |
| return ForStatement::Make(this->context(), Position(), ForLoopPositions{}, |
| std::move(initializer), std::move(test), std::move(next), |
| std::move(body), std::move(unrollInfo), fSymbolTable); |
| } |
| case Rehydrator::kIf_Command: { |
| bool isStatic = this->readU8(); |
| std::unique_ptr<Expression> test = this->expression(); |
| std::unique_ptr<Statement> ifTrue = this->statement(); |
| std::unique_ptr<Statement> ifFalse = this->statement(); |
| return IfStatement::Make(this->context(), Position(), isStatic, std::move(test), |
| std::move(ifTrue), std::move(ifFalse)); |
| } |
| case Rehydrator::kNop_Command: |
| return std::make_unique<SkSL::Nop>(); |
| case Rehydrator::kReturn_Command: { |
| std::unique_ptr<Expression> expr = this->expression(); |
| return ReturnStatement::Make(Position(), std::move(expr)); |
| } |
| case Rehydrator::kSwitch_Command: { |
| bool isStatic = this->readU8(); |
| AutoRehydratorSymbolTable symbols(this); |
| std::unique_ptr<Expression> expr = this->expression(); |
| int caseCount = this->readU8(); |
| StatementArray cases; |
| cases.reserve_back(caseCount); |
| for (int i = 0; i < caseCount; ++i) { |
| bool isDefault = this->readU8(); |
| if (isDefault) { |
| std::unique_ptr<Statement> statement = this->statement(); |
| cases.push_back(SwitchCase::MakeDefault(Position(), std::move(statement))); |
| } else { |
| SKSL_INT value = this->readS32(); |
| std::unique_ptr<Statement> statement = this->statement(); |
| cases.push_back(SwitchCase::Make(Position(), std::move(value), |
| std::move(statement))); |
| } |
| } |
| return SwitchStatement::Make(this->context(), Position(), isStatic, std::move(expr), |
| std::move(cases), fSymbolTable); |
| } |
| case Rehydrator::kVarDeclaration_Command: { |
| Variable* var = this->symbolRef<Variable>(); |
| const Type* baseType = this->type(); |
| int arraySize = this->readU8(); |
| std::unique_ptr<Expression> value = this->expression(); |
| return VarDeclaration::Make(this->context(), var, baseType, arraySize, |
| std::move(value)); |
| } |
| case Rehydrator::kVoid_Command: |
| return nullptr; |
| default: |
| printf("unsupported statement %d\n", kind); |
| SkASSERT(false); |
| return nullptr; |
| } |
| } |
| |
| ExpressionArray Rehydrator::expressionArray() { |
| uint8_t count = this->readU8(); |
| ExpressionArray array; |
| array.reserve_back(count); |
| for (int i = 0; i < count; ++i) { |
| array.push_back(this->expression()); |
| } |
| return array; |
| } |
| |
| std::unique_ptr<Expression> Rehydrator::expression() { |
| Position pos; |
| int kind = this->readU8(); |
| switch (kind) { |
| case Rehydrator::kBinary_Command: { |
| std::unique_ptr<Expression> left = this->expression(); |
| Operator::Kind op = (Operator::Kind)this->readU8(); |
| std::unique_ptr<Expression> right = this->expression(); |
| return BinaryExpression::Make(this->context(), pos, std::move(left), op, |
| std::move(right)); |
| } |
| case Rehydrator::kBoolLiteral_Command: { |
| bool value = this->readU8(); |
| return Literal::MakeBool(this->context(), pos, value); |
| } |
| case Rehydrator::kConstructorArray_Command: { |
| const Type* type = this->type(); |
| return ConstructorArray::Make(this->context(), pos, *type, this->expressionArray()); |
| } |
| case Rehydrator::kConstructorArrayCast_Command: { |
| const Type* type = this->type(); |
| ExpressionArray args = this->expressionArray(); |
| SkASSERT(args.size() == 1); |
| return ConstructorArrayCast::Make(this->context(), pos, *type, std::move(args[0])); |
| } |
| case Rehydrator::kConstructorCompound_Command: { |
| const Type* type = this->type(); |
| return ConstructorCompound::Make(this->context(), pos, *type, this->expressionArray()); |
| } |
| case Rehydrator::kConstructorDiagonalMatrix_Command: { |
| const Type* type = this->type(); |
| ExpressionArray args = this->expressionArray(); |
| SkASSERT(args.size() == 1); |
| return ConstructorDiagonalMatrix::Make(this->context(), pos, *type, std::move(args[0])); |
| } |
| case Rehydrator::kConstructorMatrixResize_Command: { |
| const Type* type = this->type(); |
| ExpressionArray args = this->expressionArray(); |
| SkASSERT(args.size() == 1); |
| return ConstructorMatrixResize::Make(this->context(), pos, *type, std::move(args[0])); |
| } |
| case Rehydrator::kConstructorScalarCast_Command: { |
| const Type* type = this->type(); |
| ExpressionArray args = this->expressionArray(); |
| SkASSERT(args.size() == 1); |
| return ConstructorScalarCast::Make(this->context(), pos, *type, std::move(args[0])); |
| } |
| case Rehydrator::kConstructorSplat_Command: { |
| const Type* type = this->type(); |
| ExpressionArray args = this->expressionArray(); |
| SkASSERT(args.size() == 1); |
| return ConstructorSplat::Make(this->context(), pos, *type, std::move(args[0])); |
| } |
| case Rehydrator::kConstructorStruct_Command: { |
| const Type* type = this->type(); |
| return ConstructorStruct::Make(this->context(), pos, *type, this->expressionArray()); |
| } |
| case Rehydrator::kConstructorCompoundCast_Command: { |
| const Type* type = this->type(); |
| ExpressionArray args = this->expressionArray(); |
| SkASSERT(args.size() == 1); |
| return ConstructorCompoundCast::Make(this->context(), pos, *type, std::move(args[0])); |
| } |
| case Rehydrator::kFieldAccess_Command: { |
| std::unique_ptr<Expression> base = this->expression(); |
| int index = this->readU8(); |
| FieldAccess::OwnerKind ownerKind = (FieldAccess::OwnerKind) this->readU8(); |
| return FieldAccess::Make(this->context(), pos, std::move(base), index, ownerKind); |
| } |
| case Rehydrator::kFloatLiteral_Command: { |
| const Type* type = this->type(); |
| int32_t floatBits = this->readS32(); |
| float value; |
| memcpy(&value, &floatBits, sizeof(value)); |
| return Literal::MakeFloat(pos, value, type); |
| } |
| case Rehydrator::kFunctionCall_Command: { |
| const Type* type = this->type(); |
| const Symbol* symbol = this->possiblyBuiltinSymbolRef(); |
| ExpressionArray args = this->expressionArray(); |
| const FunctionDeclaration* f; |
| if (symbol->is<FunctionDeclaration>()) { |
| f = &symbol->as<FunctionDeclaration>(); |
| } else if (symbol->is<UnresolvedFunction>()) { |
| const UnresolvedFunction& unresolved = symbol->as<UnresolvedFunction>(); |
| f = FunctionCall::FindBestFunctionForCall(this->context(), unresolved.functions(), |
| args); |
| SkASSERT(f); |
| } else { |
| SkASSERT(false); |
| return nullptr; |
| } |
| return FunctionCall::Make(this->context(), pos, type, *f, std::move(args)); |
| } |
| case Rehydrator::kIndex_Command: { |
| std::unique_ptr<Expression> base = this->expression(); |
| std::unique_ptr<Expression> index = this->expression(); |
| return IndexExpression::Make(this->context(), pos, std::move(base), std::move(index)); |
| } |
| case Rehydrator::kIntLiteral_Command: { |
| const Type* type = this->type(); |
| if (type->isUnsigned()) { |
| unsigned int value = this->readU32(); |
| return Literal::MakeInt(pos, value, type); |
| } else { |
| int value = this->readS32(); |
| return Literal::MakeInt(pos, value, type); |
| } |
| } |
| case Rehydrator::kPostfix_Command: { |
| Operator::Kind op = (Operator::Kind)this->readU8(); |
| std::unique_ptr<Expression> operand = this->expression(); |
| return PostfixExpression::Make(this->context(), pos, std::move(operand), op); |
| } |
| case Rehydrator::kPrefix_Command: { |
| Operator::Kind op = (Operator::Kind)this->readU8(); |
| std::unique_ptr<Expression> operand = this->expression(); |
| return PrefixExpression::Make(this->context(), pos, op, std::move(operand)); |
| } |
| case Rehydrator::kSetting_Command: { |
| std::string name(this->readString()); |
| return Setting::Convert(this->context(), pos, name); |
| } |
| case Rehydrator::kSwizzle_Command: { |
| std::unique_ptr<Expression> base = this->expression(); |
| int count = this->readU8(); |
| ComponentArray components; |
| for (int i = 0; i < count; ++i) { |
| components.push_back(this->readU8()); |
| } |
| return Swizzle::Make(this->context(), pos, std::move(base), components); |
| } |
| case Rehydrator::kTernary_Command: { |
| std::unique_ptr<Expression> test = this->expression(); |
| std::unique_ptr<Expression> ifTrue = this->expression(); |
| std::unique_ptr<Expression> ifFalse = this->expression(); |
| return TernaryExpression::Make(this->context(), pos, std::move(test), |
| std::move(ifTrue), std::move(ifFalse)); |
| } |
| case Rehydrator::kVariableReference_Command: { |
| const Variable* var = &this->possiblyBuiltinSymbolRef()->as<Variable>(); |
| VariableReference::RefKind refKind = (VariableReference::RefKind) this->readU8(); |
| return VariableReference::Make(pos, var, refKind); |
| } |
| case Rehydrator::kVoid_Command: |
| return nullptr; |
| default: |
| printf("unsupported expression %d\n", kind); |
| SkASSERT(false); |
| return nullptr; |
| } |
| } |
| |
| std::shared_ptr<SymbolTable> Rehydrator::symbolTable() { |
| int command = this->readU8(); |
| if (command == kVoid_Command) { |
| return nullptr; |
| } |
| SkASSERT(command == kSymbolTable_Command); |
| bool builtin = this->readU8(); |
| uint16_t ownedCount = this->readU16(); |
| fSymbolTable = std::make_shared<SymbolTable>(std::move(fSymbolTable), builtin); |
| std::vector<const Symbol*> ownedSymbols; |
| ownedSymbols.reserve(ownedCount); |
| for (int i = 0; i < ownedCount; ++i) { |
| ownedSymbols.push_back(this->symbol()); |
| } |
| uint16_t symbolCount = this->readU16(); |
| std::vector<std::pair<std::string_view, int>> symbols; |
| symbols.reserve(symbolCount); |
| for (int i = 0; i < symbolCount; ++i) { |
| int index = this->readU16(); |
| if (index != kBuiltin_Symbol) { |
| fSymbolTable->addWithoutOwnership(ownedSymbols[index]); |
| } else { |
| std::string_view name = this->readString(); |
| SymbolTable* root = fSymbolTable.get(); |
| while (root->fParent) { |
| root = root->fParent.get(); |
| } |
| const Symbol* s = (*root)[name]; |
| SkASSERT(s); |
| fSymbolTable->addWithoutOwnership(s); |
| } |
| } |
| return fSymbolTable; |
| } |
| |
| } // namespace SkSL |