Skip to content

Commit 92cc96a

Browse files
dpjudasRicardoLuis0
authored andcommitted
Add VMCallScript template for calling ZScript functions with type checking
1 parent b4c3d23 commit 92cc96a

File tree

2 files changed

+300
-0
lines changed

2 files changed

+300
-0
lines changed

src/common/scripting/vm/vm.h

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,236 @@ inline int VMCallAction(VMFunction *func, VMValue *params, int numparams, VMRetu
534534
return VMCall(func, params, numparams, results, numresults);
535535
}
536536

537+
template<typename T> struct VMReturnTypeTrait { typedef T type; static const int ReturnCount = 1; };
538+
template<> struct VMReturnTypeTrait<void> { typedef void type; static const int ReturnCount = 0; };
539+
540+
void VMCheckParamCount(VMFunction* func, int retcount, int argcount);
541+
542+
template<typename RetVal>
543+
void VMCheckParamCount(VMFunction* func, int argcount) { return VMCheckParamCount(func, VMReturnTypeTrait<RetVal>::ReturnCount, argcount); }
544+
545+
// The type can't be mapped to ZScript automatically:
546+
547+
template<typename NativeType> void VMCheckParam(VMFunction* func, int index) = delete;
548+
template<typename NativeType> void VMCheckReturn(VMFunction* func) = delete;
549+
550+
// Native types we support converting to/from:
551+
552+
template<> void VMCheckParam<int>(VMFunction* func, int index);
553+
template<> void VMCheckParam<double>(VMFunction* func, int index);
554+
template<> void VMCheckParam<FString>(VMFunction* func, int index);
555+
template<> void VMCheckParam<DObject*>(VMFunction* func, int index);
556+
557+
template<> void VMCheckReturn<void>(VMFunction* func);
558+
template<> void VMCheckReturn<int>(VMFunction* func);
559+
template<> void VMCheckReturn<double>(VMFunction* func);
560+
template<> void VMCheckReturn<FString>(VMFunction* func);
561+
template<> void VMCheckReturn<DObject*>(VMFunction* func);
562+
563+
template<typename RetVal> void VMValidateSignature(VMFunction* func)
564+
{
565+
VMCheckParamCount<RetVal>(func, 0);
566+
VMCheckReturn<RetVal>(func);
567+
}
568+
569+
template<typename RetVal, typename P1> void VMValidateSignature(VMFunction* func)
570+
{
571+
VMCheckParamCount<RetVal>(func, 1);
572+
VMCheckReturn<RetVal>(func);
573+
VMCheckParam<P1>(func, 0);
574+
}
575+
576+
template<typename RetVal, typename P1, typename P2> void VMValidateSignature(VMFunction* func)
577+
{
578+
VMCheckParamCount<RetVal>(func, 2);
579+
VMCheckReturn<RetVal>(func);
580+
VMCheckParam<P1>(func, 0);
581+
VMCheckParam<P2>(func, 1);
582+
}
583+
584+
template<typename RetVal, typename P1, typename P2, typename P3> void VMValidateSignature(VMFunction* func)
585+
{
586+
VMCheckParamCount<RetVal>(func, 3);
587+
VMCheckReturn<RetVal>(func);
588+
VMCheckParam<P1>(func, 0);
589+
VMCheckParam<P2>(func, 1);
590+
VMCheckParam<P3>(func, 2);
591+
}
592+
593+
template<typename RetVal, typename P1, typename P2, typename P3, typename P4> void VMValidateSignature(VMFunction* func)
594+
{
595+
VMCheckParamCount<RetVal>(func, 4);
596+
VMCheckReturn<RetVal>(func);
597+
VMCheckParam<P1>(func, 0);
598+
VMCheckParam<P2>(func, 1);
599+
VMCheckParam<P3>(func, 2);
600+
VMCheckParam<P4>(func, 3);
601+
}
602+
603+
template<typename RetVal, typename P1, typename P2, typename P3, typename P4, typename P5> void VMValidateSignature(VMFunction* func)
604+
{
605+
VMCheckParamCount<RetVal>(func, 5);
606+
VMCheckReturn<RetVal>(func);
607+
VMCheckParam<P1>(func, 0);
608+
VMCheckParam<P2>(func, 1);
609+
VMCheckParam<P3>(func, 2);
610+
VMCheckParam<P4>(func, 3);
611+
VMCheckParam<P5>(func, 4);
612+
}
613+
614+
template<typename RetVal, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6> void VMValidateSignature(VMFunction* func)
615+
{
616+
VMCheckParamCount<RetVal>(func, 6);
617+
VMCheckReturn<RetVal>(func);
618+
VMCheckParam<P1>(func, 0);
619+
VMCheckParam<P2>(func, 1);
620+
VMCheckParam<P3>(func, 2);
621+
VMCheckParam<P4>(func, 3);
622+
VMCheckParam<P5>(func, 4);
623+
VMCheckParam<P6>(func, 5);
624+
}
625+
626+
template<typename RetVal, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7> void VMValidateSignature(VMFunction* func)
627+
{
628+
VMCheckParamCount<RetVal>(func, 7);
629+
VMCheckReturn<RetVal>(func);
630+
VMCheckParam<P1>(func, 0);
631+
VMCheckParam<P2>(func, 1);
632+
VMCheckParam<P3>(func, 2);
633+
VMCheckParam<P4>(func, 3);
634+
VMCheckParam<P5>(func, 4);
635+
VMCheckParam<P6>(func, 5);
636+
VMCheckParam<P7>(func, 6);
637+
}
638+
639+
void VMCallCheckResult(VMFunction* func, VMValue* params, int numparams, VMReturn* results, int numresults);
640+
641+
template<typename RetVal, typename P1>
642+
typename VMReturnTypeTrait<RetVal>::type VMCallScript(VMFunction* func, P1 p1)
643+
{
644+
VMValidateSignature<RetVal, P1>(func);
645+
VMValue params[] = { p1 };
646+
RetVal resultval; VMReturn results(&resultval);
647+
VMCallCheckResult(func, params, 1, &results, 1);
648+
return resultval;
649+
}
650+
651+
template<typename RetVal, typename P1, typename P2>
652+
typename VMReturnTypeTrait<RetVal>::type VMCallScript(VMFunction* func, P1 p1, P2 p2)
653+
{
654+
VMValidateSignature<RetVal, P1, P2>(func);
655+
VMValue params[] = { p1, p2 };
656+
RetVal resultval; VMReturn results(&resultval);
657+
VMCallCheckResult(func, params, 2, &results, 1);
658+
return resultval;
659+
}
660+
661+
template<typename RetVal, typename P1, typename P2, typename P3>
662+
typename VMReturnTypeTrait<RetVal>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3)
663+
{
664+
VMValidateSignature<RetVal, P1, P2, P3>(func);
665+
VMValue params[] = { p1, p2, p3 };
666+
RetVal resultval; VMReturn results(&resultval);
667+
VMCallCheckResult(func, params, 3, &results, 1);
668+
return resultval;
669+
}
670+
671+
template<typename RetVal, typename P1, typename P2, typename P3, typename P4>
672+
typename VMReturnTypeTrait<RetVal>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3, P4 p4)
673+
{
674+
VMValidateSignature<RetVal, P1, P2, P3, P4>(func);
675+
VMValue params[] = { p1, p2, p3, p4 };
676+
RetVal resultval; VMReturn results(&resultval);
677+
VMCallCheckResult(func, params, 4, &results, 1);
678+
return resultval;
679+
}
680+
681+
template<typename RetVal, typename P1, typename P2, typename P3, typename P4, typename P5>
682+
typename VMReturnTypeTrait<RetVal>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
683+
{
684+
VMValidateSignature<RetVal, P1, P2, P3, P4, P5>(func);
685+
VMValue params[] = { p1, p2, p3, p4, p5 };
686+
RetVal resultval; VMReturn results(&resultval);
687+
VMCallCheckResult(func, params, 5, &results, 1);
688+
return resultval;
689+
}
690+
691+
template<typename RetVal, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
692+
typename VMReturnTypeTrait<RetVal>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
693+
{
694+
VMValidateSignature<RetVal, P1, P2, P3, P4, P5, P6>(func);
695+
VMValue params[] = { p1, p2, p3, p4, p5, p6 };
696+
RetVal resultval; VMReturn results(&resultval);
697+
VMCallCheckResult(func, params, 6, &results, 1);
698+
return resultval;
699+
}
700+
701+
template<typename RetVal, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
702+
typename VMReturnTypeTrait<RetVal>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7)
703+
{
704+
VMValidateSignature<RetVal, P1, P2, P3, P4, P5, P6, P7>(func);
705+
VMValue params[] = { p1, p2, p3, p4, p5, p6, p7 };
706+
RetVal resultval; VMReturn results(&resultval);
707+
VMCallCheckResult(func, params, 7, &results, 1);
708+
return resultval;
709+
}
710+
711+
template<typename P1>
712+
typename VMReturnTypeTrait<void>::type VMCallScript(VMFunction* func, P1 p1)
713+
{
714+
VMValidateSignature<void, P1>(func);
715+
VMValue params[1] = { p1 };
716+
VMCallCheckResult(func, params, 1, nullptr, 0);
717+
}
718+
719+
template<typename P1, typename P2>
720+
typename VMReturnTypeTrait<void>::type VMCallScript(VMFunction* func, P1 p1, P2 p2)
721+
{
722+
VMValidateSignature<void, P1, P2>(func);
723+
VMValue params[] = { p1, p2 };
724+
VMCallCheckResult(func, params, 2, nullptr, 0);
725+
}
726+
727+
template<typename P1, typename P2, typename P3>
728+
typename VMReturnTypeTrait<void>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3)
729+
{
730+
VMValidateSignature<void, P1, P2, P3>(func);
731+
VMValue params[] = { p1, p2, p3 };
732+
VMCallCheckResult(func, params, 3, nullptr, 0);
733+
}
734+
735+
template<typename P1, typename P2, typename P3, typename P4>
736+
typename VMReturnTypeTrait<void>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3, P4 p4)
737+
{
738+
VMValidateSignature<void, P1, P2, P3, P4>(func);
739+
VMValue params[] = { p1, p2, p3, p4 };
740+
VMCallCheckResult(func, params, 4, nullptr, 0);
741+
}
742+
743+
template<typename P1, typename P2, typename P3, typename P4, typename P5>
744+
typename VMReturnTypeTrait<void>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
745+
{
746+
VMValidateSignature<void, P1, P2, P3, P4, P5>(func);
747+
VMValue params[] = { p1, p2, p3, p4, p5 };
748+
VMCallCheckResult(func, params, 5, nullptr, 0);
749+
}
750+
751+
template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
752+
typename VMReturnTypeTrait<void>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
753+
{
754+
VMValidateSignature<void, P1, P2, P3, P4, P5, P6>(func);
755+
VMValue params[] = { p1, p2, p3, p4, p5, p6 };
756+
VMCallCheckResult(func, params, 6, nullptr, 0);
757+
}
758+
759+
template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
760+
typename VMReturnTypeTrait<void>::type VMCallScript(VMFunction* func, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7)
761+
{
762+
VMValidateSignature<void, P1, P2, P3, P4, P5, P6, P7>(func);
763+
VMValue params[] = { p1, p2, p3, p4, p5, p6, p7 };
764+
VMCallCheckResult(func, params, 7, nullptr, 0);
765+
}
766+
537767
// Use these to collect the parameters in a native function.
538768
// variable name <x> at position <p>
539769
[[noreturn]]

src/common/scripting/vm/vmframe.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,76 @@ VMFrame *VMFrameStack::PopFrame()
552552
return parent;
553553
}
554554

555+
//===========================================================================
556+
// Templates for calling ZScript from C++ with type checks
557+
558+
void VMCheckParamCount(VMFunction* func, int retcount, int argcount)
559+
{
560+
if (func->Proto->ReturnTypes.Size() != retcount)
561+
I_FatalError("Incorrect return value passed to %s", func->PrintableName);
562+
if (func->Proto->ArgumentTypes.Size() != argcount)
563+
I_FatalError("Incorrect parameter count passed to %s", func->PrintableName);
564+
}
565+
566+
template<> void VMCheckParam<int>(VMFunction* func, int index)
567+
{
568+
if (!func->Proto->ArgumentTypes[index]->isIntCompatible())
569+
I_FatalError("%s argument %d is not an integer", func->PrintableName);
570+
}
571+
572+
template<> void VMCheckParam<double>(VMFunction* func, int index)
573+
{
574+
if (func->Proto->ArgumentTypes[index] != TypeFloat64)
575+
I_FatalError("%s argument %d is not a double", func->PrintableName);
576+
}
577+
578+
template<> void VMCheckParam<FString>(VMFunction* func, int index)
579+
{
580+
if (func->Proto->ArgumentTypes[index] != TypeString)
581+
I_FatalError("%s argument %d is not a string", func->PrintableName);
582+
}
583+
584+
template<> void VMCheckParam<DObject*>(VMFunction* func, int index)
585+
{
586+
if (func->Proto->ArgumentTypes[index]->isObjectPointer())
587+
I_FatalError("%s argument %d is not an object", func->PrintableName);
588+
}
589+
590+
template<> void VMCheckReturn<void>(VMFunction* func)
591+
{
592+
}
593+
594+
template<> void VMCheckReturn<int>(VMFunction* func)
595+
{
596+
if (!func->Proto->ReturnTypes[0]->isIntCompatible())
597+
I_FatalError("%s return value %d is not an integer", func->PrintableName);
598+
}
599+
600+
template<> void VMCheckReturn<double>(VMFunction* func)
601+
{
602+
if (func->Proto->ReturnTypes[0] != TypeFloat64)
603+
I_FatalError("%s return value %d is not a double", func->PrintableName);
604+
}
605+
606+
template<> void VMCheckReturn<FString>(VMFunction* func)
607+
{
608+
if (func->Proto->ReturnTypes[0] != TypeString)
609+
I_FatalError("%s return value %d is not a string", func->PrintableName);
610+
}
611+
612+
template<> void VMCheckReturn<DObject*>(VMFunction* func)
613+
{
614+
if (func->Proto->ReturnTypes[0]->isObjectPointer())
615+
I_FatalError("%s return value %d is not an object", func->PrintableName);
616+
}
617+
618+
void VMCallCheckResult(VMFunction* func, VMValue* params, int numparams, VMReturn* results, int numresults)
619+
{
620+
int retval = VMCall(func, params, numparams, results, numresults);
621+
if (retval != numresults)
622+
I_FatalError("%s did not return the expected number of results", func->PrintableName);
623+
}
624+
555625
//===========================================================================
556626
//
557627
// VMFrameStack :: Call

0 commit comments

Comments
 (0)