Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler self call support #1683

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 77 additions & 20 deletions UndertaleModLib/Compiler/AssemblyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,17 @@ private static void AssembleStatement(CodeWriter cw, Parser.Statement s, int rem
case Parser.Statement.StatementKind.Exit:
AssembleExit(cw);
break;
case Parser.Statement.StatementKind.ExprVariableRef:
for (int i = s.Children.Count - 1; i >= 1; i--)
{
if (s.Children[i].Kind == Parser.Statement.StatementKind.ExprFunctionCall)
{
PushFunctionArgs(cw, s.Children[i]);
}
}
AssembleVariablePush(cw, s);
cw.Emit(Opcode.Popz, cw.typeStack.Pop());
break;
default:
AssemblyWriterError(cw, "Expected a statement, none found", s.Token);
break;
Expand Down Expand Up @@ -1158,7 +1169,7 @@ private static void AssembleExit(CodeWriter cw)
cw.Emit(Opcode.Exit, DataType.Int32);
}

private static void AssembleFunctionCall(CodeWriter cw, Parser.Statement fc)
private static void PushFunctionArgs(CodeWriter cw, Parser.Statement fc)
{
// Needs to push args onto stack backwards
for (int i = fc.Children.Count - 1; i >= 0; i--)
Expand All @@ -1172,13 +1183,42 @@ private static void AssembleFunctionCall(CodeWriter cw, Parser.Statement fc)
cw.Emit(Opcode.Conv, typeToConvertFrom, DataType.Variable);
}
}
}

private static void AssembleFunctionCall(CodeWriter cw, Parser.Statement fc, bool isVariableCall = false, bool isSelf = false) {
if (!isVariableCall)
{
PushFunctionArgs(cw, fc);
}

cw.funcPatches.Add(new FunctionPatch()
if (isVariableCall)
{
Target = cw.EmitRef(Opcode.Call, DataType.Int32),
Name = fc.Text,
ArgCount = fc.Children.Count
});
/*
dup.v 3 8 ;;; this is a weird GMS2.3+ swap instruction
dup.v 0
push.v stacktop.on_room_start
callv.v 3
*/
byte argCount = (byte)(fc.Children.Count);

// this is still a total mess
int varId = cw.compileContext.GetAssetIndexByName(fc.Text);
Parser.Statement funcVar = new Parser.Statement(Parser.Statement.StatementKind.ExprSingleVariable);
funcVar.ID = varId;
funcVar.Text = fc.Text;
AssembleVariablePush(cw, funcVar, false, false, false, true);

cw.Emit(Opcode.CallV, DataType.Variable, DataType.Variable).Extra = argCount;
}
else
{
cw.funcPatches.Add(new FunctionPatch()
{
Target = cw.EmitRef(Opcode.Call, DataType.Int32),
Name = fc.Text,
ArgCount = fc.Children.Count
});
}
cw.typeStack.Push(DataType.Variable);
}

Expand Down Expand Up @@ -1700,18 +1740,18 @@ private static void ConvertTypeForBinaryOp(CodeWriter cw, Lexer.Token.TokenKind
}

// Workaround for out parameters
private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, bool duplicate = false, bool useLongDupForArray = false, bool useNoSpecificType = false)
private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, bool duplicate = false, bool useLongDupForArray = false, bool useNoSpecificType = false, bool forceBuiltin = false)
{
AssembleVariablePush(cw, e, out _, out _, duplicate, useLongDupForArray, useNoSpecificType);
AssembleVariablePush(cw, e, out _, out _, duplicate, useLongDupForArray, useNoSpecificType, forceBuiltin);
}

// Workaround for out parameters #2
private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out bool isSingle, bool duplicate = false, bool useLongDupForArray = false, bool useNoSpecificType = false)
private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out bool isSingle, bool duplicate = false, bool useLongDupForArray = false, bool useNoSpecificType = false, bool forceBuiltin = false)
{
AssembleVariablePush(cw, e, out isSingle, out _, duplicate, useLongDupForArray, useNoSpecificType);
AssembleVariablePush(cw, e, out isSingle, out _, duplicate, useLongDupForArray, useNoSpecificType, forceBuiltin);
}

private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out bool isSingle, out bool isArray, bool duplicate = false, bool useLongDupForArray = false, bool useNoSpecificType = false)
private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out bool isSingle, out bool isArray, bool duplicate = false, bool useLongDupForArray = false, bool useNoSpecificType = false, bool forceBuiltin = false)
{
isSingle = false;
isArray = false;
Expand Down Expand Up @@ -1770,7 +1810,7 @@ private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out
{
Target = cw.EmitRef(Opcode.Push, DataType.Variable),
Name = e.Children[0].Text,
InstType = GetIDPrefixSpecial(e.Children[0].ID),
InstType = forceBuiltin ? InstanceType.Builtin : GetIDPrefixSpecial(e.Children[0].ID),
VarType = VariableType.Array
});
}
Expand Down Expand Up @@ -1822,7 +1862,7 @@ private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out
{
Target = cw.EmitRef(Opcode.Push, DataType.Variable),
Name = name,
InstType = InstanceType.Self,
InstType = forceBuiltin ? InstanceType.Builtin : InstanceType.Self,
VarType = VariableType.Normal
});
}
Expand Down Expand Up @@ -1850,7 +1890,7 @@ private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out
{
Target = cw.EmitRef(Opcode.Push, DataType.Variable),
Name = name,
InstType = (InstanceType)id,
InstType = forceBuiltin ? InstanceType.Builtin : (InstanceType)id,
VarType = VariableType.Normal
});
break;
Expand All @@ -1862,8 +1902,11 @@ private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out
AssembleExpression(cw, e.Children[0]);
if (CompileContext.GMS2_3 && cw.typeStack.Peek() == DataType.Variable)
{
cw.typeStack.Pop();
cw.Emit(Opcode.PushI, DataType.Int16).Value = (short)-9; // stacktop conversion
if (e.Children.Count < 1 || e.Children[1].Kind != Parser.Statement.StatementKind.ExprFunctionCall)
{
cw.typeStack.Pop();
cw.Emit(Opcode.PushI, DataType.Int16).Value = (short)-9; // stacktop conversion
}
}
else if (cw.typeStack.Peek() != DataType.Int32) // apparently it converts to ints
{
Expand All @@ -1872,8 +1915,16 @@ private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out

for (int next = 1; next < e.Children.Count; next++)
{
if (e.Children[next].Children.Count != 0)
if (e.Children[next].Children.Count != 0 || e.Children[next].Kind == Parser.Statement.StatementKind.ExprFunctionCall)
{
if (e.Children[next].Kind == Parser.Statement.StatementKind.ExprFunctionCall)
{
// Function call
AssembleFunctionCall(cw, e.Children[next], true, false);
cw.typeStack.Push(DataType.Variable);
continue;
}

AssembleArrayPush(cw, e.Children[next]);
bool notLast = (next + 1 < e.Children.Count);
if (!notLast && duplicate) // ha ha, double negatives
Expand All @@ -1887,7 +1938,7 @@ private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out
{
Target = cw.EmitRef(Opcode.Push, DataType.Variable),
Name = e.Children[next].Text,
InstType = GetIDPrefixSpecial(e.Children[next].ID),
InstType = forceBuiltin ? InstanceType.Builtin : GetIDPrefixSpecial(e.Children[next].ID),
VarType = VariableType.Array
});
cw.typeStack.Push(DataType.Variable);
Expand Down Expand Up @@ -1938,7 +1989,7 @@ private static void AssembleVariablePush(CodeWriter cw, Parser.Statement e, out
}
}
fix.Children.Add(fix2);
AssembleVariablePush(cw, fix, out isSingle, out isArray, duplicate, useLongDupForArray, useNoSpecificType);
AssembleVariablePush(cw, fix, out isSingle, out isArray, duplicate, useLongDupForArray, useNoSpecificType, forceBuiltin);
}
else
{
Expand Down Expand Up @@ -2198,10 +2249,16 @@ private static void AssembleStoreVariable(CodeWriter cw, Parser.Statement s, Dat
else if (s.Kind == Parser.Statement.StatementKind.ExprFuncName)
{
// Until further notice, I'm assuming this only comes up in 2.3 script definition.

// sub funcs in an object store the self variable without the object function name suffix
string funcName = s.Text;
if (funcName.Contains("_gml_Object_"))
funcName = funcName[..funcName.LastIndexOf("_gml_Object_")];

cw.varPatches.Add(new VariablePatch()
{
Target = cw.EmitRef(Opcode.Pop, DataType.Variable, DataType.Variable),
Name = s.Text,
Name = funcName,
InstType = InstanceType.Self,
VarType = VariableType.StackTop
});
Expand Down
5 changes: 5 additions & 0 deletions UndertaleModLib/Compiler/Lexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,9 @@ private static Token ReadIdentifier(CodeReader cr)
"then" => new Token(Token.TokenKind.KeywordThen, cr.GetPositionInfo(index)),
"mod" => new Token(Token.TokenKind.Mod, cr.GetPositionInfo(index)),
"div" => new Token(Token.TokenKind.Div, cr.GetPositionInfo(index)),
// In GMS2.3, these keywords are special function calls instead of constants
"self" when CompileContext.GMS2_3 => new Token(Token.TokenKind.KeywordSelf, cr.GetPositionInfo(index)),
"other" when CompileContext.GMS2_3 => new Token(Token.TokenKind.KeywordOther, cr.GetPositionInfo(index)),
_ => new Token(Token.TokenKind.Identifier, identifierText, cr.GetPositionInfo(index)),
};
}
Expand Down Expand Up @@ -813,6 +816,8 @@ public enum TokenKind
KeywordContinue,
KeywordStruct, // Apparently this exists
KeywordFunction,
KeywordSelf,
KeywordOther,
OpenBlock, // {
CloseBlock, // }
OpenArray, // [
Expand Down
Loading