diff --git a/src/common/engine/sc_man.cpp b/src/common/engine/sc_man.cpp index 9849c2e21..ac7b4799f 100644 --- a/src/common/engine/sc_man.cpp +++ b/src/common/engine/sc_man.cpp @@ -260,6 +260,7 @@ void FScanner::PrepareScript () StateOptions = false; StringBuffer[0] = '\0'; BigStringBuffer = ""; + ParseError = false; } //========================================================================== @@ -1089,13 +1090,14 @@ void FScanner::ScriptError (const char *message, ...) va_end (arglist); } + ParseError = true; if (NoFatalErrors) { - Printf(TEXTCOLOR_RED "Script error, \"%s\"" TEXTCOLOR_RED " line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(), + Printf(TEXTCOLOR_RED "%sScript error, \"%s\"" TEXTCOLOR_RED " line %d:\n" TEXTCOLOR_RED "%s\n", PrependMessage.GetChars(), ScriptName.GetChars(), AlreadyGot ? AlreadyGotLine : Line, composed.GetChars()); return; } - I_Error ("Script error, \"%s\" line %d:\n%s\n", ScriptName.GetChars(), + I_Error ("%sScript error, \"%s\" line %d:\n%s\n", PrependMessage.GetChars(), ScriptName.GetChars(), AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); } @@ -1121,7 +1123,8 @@ void FScanner::ScriptMessage (const char *message, ...) va_end (arglist); } - Printf (TEXTCOLOR_RED "Script error, \"%s\"" TEXTCOLOR_RED " line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(), + ParseError = true; + Printf (TEXTCOLOR_RED "%sScript error, \"%s\"" TEXTCOLOR_RED " line %d:\n" TEXTCOLOR_RED "%s\n", PrependMessage.GetChars(), ScriptName.GetChars(), AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); } @@ -1383,4 +1386,3 @@ int ParseHex(const char* hex, FScriptPosition* sc) return num; } - diff --git a/src/common/engine/sc_man.h b/src/common/engine/sc_man.h index 32848a4a6..5873523a1 100644 --- a/src/common/engine/sc_man.h +++ b/src/common/engine/sc_man.h @@ -192,6 +192,7 @@ public: void ScriptError(const char *message, ...) GCCPRINTF(2,3); void ScriptMessage(const char *message, ...) GCCPRINTF(2,3); + void SetPrependMessage(const FString& message) { PrependMessage = message; } bool isText(); @@ -238,6 +239,7 @@ protected: bool StateOptions; bool Escape; VersionInfo ParseVersion = { 0, 0, 0 }; // no ZScript extensions by default + FString PrependMessage = ""; bool ScanValue(bool allowfloat, bool evaluate); diff --git a/src/common/scripting/interface/vmnatives.cpp b/src/common/scripting/interface/vmnatives.cpp index 317ae6bfd..f7f4fffaf 100644 --- a/src/common/scripting/interface/vmnatives.cpp +++ b/src/common/scripting/interface/vmnatives.cpp @@ -1407,3 +1407,361 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Translation, MakeID, MakeTransID) ACTION_RETURN_INT(MakeTransID(g, t)); } +// DObject-based wrapper around FScanner, for ZScript. +class DScriptScanner : public DObject +{ + DECLARE_CLASS(DScriptScanner, DObject) +public: + FScanner wrapped; + +}; + +IMPLEMENT_CLASS(DScriptScanner, false, false); + +static void OpenLumpNum(DScriptScanner* self, int lump) { return self->wrapped.OpenLumpNum(lump); } +static void OpenString(DScriptScanner* self, const FString* name, FString* script) { return self->wrapped.OpenString(name->GetChars(), *script); } +static void SavePos(DScriptScanner* self, FScanner::SavedPos *pos) { *pos = self->wrapped.SavePos(); } +static void RestorePos(DScriptScanner* self, const FScanner::SavedPos* pos) { return self->wrapped.RestorePos(*pos); } +static void GetStringContents(DScriptScanner* self, FString* str) { *str = self->wrapped.String; } +static void UnGet(DScriptScanner* self) { return self->wrapped.UnGet(); } +static int isText(DScriptScanner* self) { return self->wrapped.isText(); } +static int GetMessageLine(DScriptScanner* self) { return self->wrapped.GetMessageLine(); } +static void Close(DScriptScanner* self) { return self->wrapped.Close(); } +static void SetCMode(DScriptScanner* self, int cmode) { return self->wrapped.SetCMode(cmode); } +static void SetNoOctals(DScriptScanner* self, int cmode) { return self->wrapped.SetNoOctals(cmode); } +static void SetEscape(DScriptScanner* self, int esc) { return self->wrapped.SetNoOctals(esc); } +static void SetNoFatalErrors(DScriptScanner* self, int cmode) { return self->wrapped.SetNoFatalErrors(cmode); } +static void AddSymbolUint(DScriptScanner* self, const FString* name, uint32_t value) { return self->wrapped.AddSymbol(name->GetChars(), value); } +static void AddSymbolInt(DScriptScanner* self, const FString* name, int32_t value) { return self->wrapped.AddSymbol(name->GetChars(), value); } +static void AddSymbolDouble(DScriptScanner* self, const FString* name, double value) { return self->wrapped.AddSymbol(name->GetChars(), value); } +static int GetString(DScriptScanner* self) { return self->wrapped.GetString(); } +static int GetNumber(DScriptScanner* self, int evaluate) { return self->wrapped.GetNumber(evaluate); } +static int GetFloat(DScriptScanner* self, int evaluate) { return self->wrapped.GetFloat(evaluate); } +static int CheckValue(DScriptScanner* self, int allowfloat, int evaluate) { return self->wrapped.CheckValue(allowfloat, evaluate); } +static int CheckNumber(DScriptScanner* self, int evaluate) { return self->wrapped.CheckNumber(evaluate); } +static int CheckBoolToken(DScriptScanner* self) { return self->wrapped.CheckBoolToken(); } +static int CheckString(DScriptScanner* self, const FString* name) { return self->wrapped.CheckString(name->GetChars()); } +static int CheckFloat(DScriptScanner* self, int evaluate) { return self->wrapped.CheckFloat(evaluate); } +static void SetPrependMessage(DScriptScanner* self, const FString* message) { return self->wrapped.SetPrependMessage(*message); } +static void SkipToEndOfBlock(DScriptScanner* self) { return self->wrapped.SkipToEndOfBlock(); } +static int StartBraces(DScriptScanner* self, FScanner::SavedPos* braceend) { return self->wrapped.StartBraces(braceend); } +static int FoundEndBrace(DScriptScanner* self, FScanner::SavedPos* braceend) { return self->wrapped.FoundEndBrace(*braceend); } +static void MustGetValue(DScriptScanner* self, int allowfloat, int evaluate) { return self->wrapped.MustGetValue(allowfloat, evaluate); } +static void MustGetFloat(DScriptScanner* self, int evaluate) { return self->wrapped.MustGetFloat(evaluate); } +static void MustGetNumber(DScriptScanner* self, int evaluate) { return self->wrapped.MustGetNumber(evaluate); } +static void MustGetString(DScriptScanner* self) { return self->wrapped.MustGetString(); } +static void MustGetStringName(DScriptScanner* self, const FString* name) { return self->wrapped.MustGetStringName(name->GetChars()); } +static void MustGetBoolToken(DScriptScanner* self) { return self->wrapped.MustGetBoolToken(); } + + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, OpenLumpNum, OpenLumpNum) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_INT(lump); + + OpenLumpNum(self, lump); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, OpenString, OpenString) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + PARAM_STRING_VAL(script); + + OpenString(self, &name, &script); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SavePos, SavePos) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_POINTER(pos, FScanner::SavedPos); + + SavePos(self, pos); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, RestorePos, RestorePos) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_POINTER(pos, FScanner::SavedPos); + + RestorePos(self, pos); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetStringContents, GetStringContents) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + ACTION_RETURN_STRING(self->wrapped.String); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, UnGet, UnGet) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + UnGet(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, isText, isText) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + ACTION_RETURN_BOOL(isText(self)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetMessageLine, GetMessageLine) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + ACTION_RETURN_INT(GetMessageLine(self)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, AddSymbol, AddSymbolInt) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + PARAM_INT(value); + + AddSymbolInt(self, &name, value); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, AddSymbolUnsigned, AddSymbolUint) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + PARAM_UINT(value); + + AddSymbolUint(self, &name, value); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, AddSymbolFloat, AddSymbolDouble) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + PARAM_FLOAT(value); + + AddSymbolDouble(self, &name, value); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetString, GetString) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + ACTION_RETURN_BOOL(GetString(self)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetNumber, GetNumber) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(GetNumber(self, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, GetFloat, GetFloat) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(GetFloat(self, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckValue, CheckValue) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(allowfloat); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(CheckValue(self, allowfloat, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckBoolToken, CheckBoolToken) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + ACTION_RETURN_BOOL(CheckBoolToken(self)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckNumber, CheckNumber) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(CheckNumber(self, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckString, CheckString) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + + ACTION_RETURN_BOOL(CheckString(self, &name)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, CheckFloat, CheckFloat) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + ACTION_RETURN_BOOL(CheckFloat(self, evaluate)); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetPrependMessage, SetPrependMessage) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(message); + + SetPrependMessage(self, &message); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetCMode, SetCMode) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(cmode); + + SetCMode(self, cmode); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetNoOctals, SetNoOctals) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(cmode); + + SetNoOctals(self, cmode); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetEscape, SetEscape) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(esc); + + SetEscape(self, esc); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SkipToEndOfBlock, SkipToEndOfBlock) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + SkipToEndOfBlock(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, StartBraces, StartBraces) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_POINTER(braceend, FScanner::SavedPos); + + StartBraces(self, braceend); // the return value of this is useless. + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, FoundEndBrace, FoundEndBrace) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_POINTER(braceend, FScanner::SavedPos); + + ACTION_RETURN_BOOL(FoundEndBrace(self, braceend)); +} + +DEFINE_ACTION_FUNCTION(DScriptScanner, ScriptError) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + FString s = FStringFormat(VM_ARGS_NAMES); + self->wrapped.ScriptError("%s", s.GetChars()); + return 0; +} + +DEFINE_ACTION_FUNCTION(DScriptScanner, ScriptMessage) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + FString s = FStringFormat(VM_ARGS_NAMES); + self->wrapped.ScriptMessage("%s", s.GetChars()); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetValue, MustGetValue) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(allowfloat); + PARAM_BOOL(evaluate); + + MustGetValue(self, allowfloat, evaluate); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetNumber, MustGetNumber) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + MustGetNumber(self, evaluate); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetFloat, MustGetFloat) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(evaluate); + + MustGetFloat(self, evaluate); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetString, MustGetString) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + MustGetString(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetStringName, MustGetStringName) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_STRING(name); + + MustGetStringName(self, &name); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, MustGetBoolToken, MustGetBoolToken) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + MustGetBoolToken(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, Close, Close) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + + Close(self); + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(DScriptScanner, SetNoFatalErrors, SetNoFatalErrors) +{ + PARAM_SELF_PROLOGUE(DScriptScanner); + PARAM_BOOL(cmode); + + SetNoFatalErrors(self, cmode); + return 0; +} + +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.Line, Line); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.Float, Float); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.Number, Number); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.End, End); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.Crossed, Crossed); +DEFINE_FIELD_NAMED_X(ScriptScanner, DScriptScanner, wrapped.ParseError, ParseError); diff --git a/wadsrc/static/zscript/engine/base.zs b/wadsrc/static/zscript/engine/base.zs index ada5fbaaf..f24b71d01 100644 --- a/wadsrc/static/zscript/engine/base.zs +++ b/wadsrc/static/zscript/engine/base.zs @@ -940,6 +940,68 @@ struct QuatStruct native // native Quat Unit(); } +struct ScriptSavedPos +{ + voidptr SavedScriptPtr; + int SavedScriptLine; +} + +class ScriptScanner native +{ + native void OpenString(String name, String script); + native void OpenLumpNum(int lump); + native void Close(); + + native void SavePos(out ScriptSavedPos pos); + native void RestorePos(out ScriptSavedPos pos); + native void UnGet(); + native bool isText(); + native int GetMessageLine(); + native void SetPrependMessage(String message); + + native vararg void ScriptError(String fmt, ...); + native vararg void ScriptMessage(String fmt, ...); + + native void SetCMode(bool cmode); + native void SetNoOctals(bool cmode); + native void SetEscape(bool esc); + native void SetNoFatalErrors(bool cmode); + native void SkipToEndOfBlock(); + native void StartBraces(out ScriptSavedPos braceend); + native bool FoundEndBrace(out ScriptSavedPos braceend); + + native bool CheckValue(bool allowfloat, bool evaluate = true); + native bool CheckBoolToken(); + native bool CheckNumber(bool evaluate = false); + native bool CheckString(String name); + native bool CheckFloat(bool evaluate = false); + + native bool GetNumber(bool evaluate = false); + native bool GetString(); + native bool GetFloat(bool evaluate = false); + + native void AddSymbol(String name, int value); + native void AddSymbolUnsigned(String name, uint value); + native void AddSymbolFloat(String name, double value); + + native void MustGetValue(bool allowfloat, bool evaluate = true); + native void MustGetFloat(bool evaluate = false); + native void MustGetNumber(bool evaluate = false); + native void MustGetString(); + native void MustGetStringName(String name); + native void MustGetBoolToken(); + + // This DOES NOT advance the parser! This returns the string the parser got. + native String GetStringContents(); + + native readonly bool End; + native readonly bool ParseError; + native readonly bool Crossed; + native readonly int Line; + native readonly int Number; + native readonly double Float; +} + // this struct does not exist. It is just a type for being referenced by an opaque pointer. struct VMFunction native version("4.10") {