Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
Relfos committed Oct 16, 2021
2 parents 1a44b9e + bb7a742 commit bc37cfd
Show file tree
Hide file tree
Showing 7 changed files with 452 additions and 86 deletions.
180 changes: 155 additions & 25 deletions Compiler/Compiler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Phantasma.Domain;
using Phantasma.Domain;
using Phantasma.Numerics;
using Phantasma.VM;
using System;
Expand Down Expand Up @@ -183,7 +183,7 @@ private VarType ExpectType()
return VarType.Find(VarKind.Enum, token.value);
}

throw new CompilerException("expected type, got " + token.kind);
throw new CompilerException($"expected type, got {token.kind} [{token.value}]");
}

if (token.value == "decimal")
Expand Down Expand Up @@ -855,6 +855,7 @@ private void ParseModule(Module module)

case "onWitness":
case "onSeries":
case "onKill":
case "onUpgrade": // address
CheckParameters(name, parameters, new[] { VarKind.Address });
break;
Expand Down Expand Up @@ -1037,6 +1038,7 @@ private MethodParameter[] ParseParameters(Scope scope)
private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)
{
var block = new StatementBlock(scope);
var terminateEarly = false;

do
{
Expand Down Expand Up @@ -1110,6 +1112,8 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)

block.Commands.Add(new ReturnStatement(method, expr));
ExpectToken(";");

terminateEarly = true;
break;
}

Expand All @@ -1124,6 +1128,8 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)

block.Commands.Add(new ThrowStatement(expr));
ExpectToken(";");

terminateEarly = true;
break;
}

Expand Down Expand Up @@ -1212,6 +1218,61 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)
break;
}

case "switch":
{
var switchCommand = new SwitchStatement(scope);

ExpectToken("(");
switchCommand.variable = ExpectExpression(scope) as VarExpression;

if (switchCommand.variable == null)
{
throw new CompilerException($"switch condition must be variable expression");
}

ExpectToken(")");

ExpectToken("{");

while (true)
{
var next = FetchToken();

if (next.value == "}")
{
break;
}
else
if (next.value == "default")
{
ExpectToken(":");
switchCommand.@default = ParseCommandBlock(switchCommand.Scope, method);
break;
}

Rewind();
ExpectToken("case");

var literal = ParseExpression(scope, false) as LiteralExpression;

if (literal == null)
{
throw new CompilerException($"switch case condition must be literal expression");
}

ExpectToken(":");

var body = ParseCommandBlock(switchCommand.Scope, method);

switchCommand.cases.Add(new CaseStatement(literal, body));
}

ExpectToken("}");

block.Commands.Add(switchCommand);
break;
}

case "while":
{
var whileCommand = new WhileStatement(scope);
Expand Down Expand Up @@ -1268,6 +1329,7 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)
ExpectToken(";");

block.Commands.Add(new BreakStatement(scope));
terminateEarly = true;
break;
}

Expand All @@ -1276,6 +1338,7 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)
ExpectToken(";");

block.Commands.Add(new ContinueStatement(scope));
terminateEarly = true;
break;
}

Expand Down Expand Up @@ -1313,30 +1376,15 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)
}

expressionExpectedType = arrayType.elementType;
setCommand.indexExpression = ParseArrayIndexingExpression(scope, tmp, expressionExpectedType);
setCommand.keyExpression = ParseArrayIndexingExpression(scope, tmp, expressionExpectedType);
}
else
{
setCommand.variable = scope.FindVariable(varName);
expressionExpectedType = setCommand.variable.Type;
}

var expr = ExpectExpression(scope);
if (next.value != ":=")
{
var str = next.value.Substring(0, next.value.Length - 1);
var op = ParseOperator(str);

if (op == OperatorKind.Unknown)
{
throw new CompilerException("unknown operator: " + next.value);
}

expr = new BinaryExpression(scope, op, new VarExpression(scope, setCommand.variable), expr);
}


expr = Expression.AutoCast(expr, expressionExpectedType);
var expr = ParseAssignmentExpression(scope, next, setCommand.variable, expressionExpectedType);

setCommand.valueExpression = expr;
block.Commands.Add(setCommand);
Expand All @@ -1345,6 +1393,7 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)
if (next.kind == TokenKind.Selector)
{
var varDecl = scope.FindVariable(token.value, false);
bool isStructField = false;

LibraryDeclaration libDecl;

Expand Down Expand Up @@ -1376,6 +1425,14 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)
break;
}

case VarKind.Struct:
{
libDecl = null;
isStructField = true;
break;
}


default:
throw new CompilerException($"expected {token.value} to be generic type, but is {varDecl.Type} instead");
}
Expand All @@ -1385,10 +1442,41 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)
libDecl = scope.Module.FindLibrary(token.value);
}

var methodCall = new MethodCallStatement();
methodCall.expression = ParseMethodExpression(scope, libDecl, varDecl);
if (isStructField)
{
var fieldName = ExpectIdentifier();

next = FetchToken();

if (next.kind == TokenKind.Operator && next.value.EndsWith("="))
{
var structName = ((StructVarType)varDecl.Type).name;
if (!_structs.ContainsKey(structName))
{
throw new CompilerException("unknown struct: " + structName);
}

var structDecl = _structs[structName];
var fieldDecl = structDecl.fields.FirstOrDefault(x => x.name == fieldName);

block.Commands.Add(methodCall);
var assignment = new AssignStatement();
assignment.variable = varDecl;
assignment.keyExpression = new LiteralExpression(scope, "\"" + fieldName + "\"" , fieldDecl.type);
assignment.valueExpression = ParseAssignmentExpression(scope, next, varDecl, fieldDecl.type);
block.Commands.Add(assignment);
}
else
{
throw new CompilerException($"expected assignment operator");
}
}
else
{
var methodCall = new MethodCallStatement();
methodCall.expression = ParseMethodExpression(scope, libDecl, varDecl);

block.Commands.Add(methodCall);
}
}
else
{
Expand All @@ -1404,9 +1492,46 @@ private StatementBlock ParseCommandBlock(Scope scope, MethodDeclaration method)

break;
}
} while (true);
} while (!terminateEarly);

if (terminateEarly)
{
if (block.Commands.Count > 1)
{
ExpectToken("}");
Rewind();
}

return block;
}
else
{
throw new CompilerException("weird compiler flow detected, contact devs");
}
}

private Expression ParseAssignmentExpression(Scope scope, LexerToken next, VarDeclaration varDecl, VarType expectedType)
{
var expr = ExpectExpression(scope);
if (next.value != ":=")
{
var str = next.value.Substring(0, next.value.Length - 1);
var op = ParseOperator(str);

if (op == OperatorKind.Unknown)
{
throw new CompilerException("unknown operator: " + next.value);
}

expr = new BinaryExpression(scope, op, new VarExpression(scope, varDecl), expr);
}


expr = Expression.AutoCast(expr, expectedType);

return expr;
}

private Expression ExpectExpression(Scope scope)
{
var expr = ParseExpression(scope);
Expand Down Expand Up @@ -1567,7 +1692,9 @@ private Expression ParseExpressionFromToken(LexerToken first, Scope scope)
Rewind();
}

return new MacroExpression(scope, first.value, args);
var macro = new MacroExpression(scope, first.value, args);

return macro.Unfold(scope);
}

default:
Expand Down Expand Up @@ -2004,6 +2131,9 @@ private MethodExpression ParseMethodExpression(Scope scope, LibraryDeclaration l
expr.arguments.Add(arg);

var expectedType = expr.method.Parameters[i].Type;

arg = Expression.AutoCast(arg, expectedType);

if (arg.ResultType != expectedType && expectedType.Kind != VarKind.Any)
{
throw new CompilerException($"expected argument of type {expectedType}, got {arg.ResultType} instead");
Expand Down
18 changes: 17 additions & 1 deletion Compiler/Declaration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ public void GenerateCode(CodeGenerator output)
// we need to fetch the global variables from storage and allocate registers for them
foreach (var variable in this.scope.Parent.Variables.Values)
{
// validate NFT implicit variables
if (variable.Storage != VarStorage.Global)
{
if (variable.Storage == VarStorage.NFT && this.scope.Module.Kind != ModuleKind.NFT)
Expand All @@ -647,12 +648,26 @@ public void GenerateCode(CodeGenerator output)
continue;
}

// for maps/lists/sets we clear them here. Should not be necessary, but just in case
// this is REQUIRED right now until chain implementation of Contract.Kill is improved
if (isConstructor && variable.Type.IsStorageBound)
{
var storageClassName = variable.Type.ToString().Replace("Storage_", "");

output.AppendLine(this, $"// clearing {variable.Name} storage");
output.AppendLine(this, $"LOAD r0 \"{variable.Name}\"");
output.AppendLine(this, $"PUSH r0");
output.AppendLine(this, "LOAD r0 \"" + storageClassName + ".Clear\"");
output.AppendLine(this, $"EXTCALL r0");
}

if (!this.IsNodeUsed(variable))
{
variable.Register = null;
continue;
}

// generate code for loading globals from contract storage via Data.Get extcall
if (tempReg1 == null && !isConstructor)
{
tempReg1 = Compiler.Instance.AllocRegister(output, this, "dataGet");
Expand All @@ -667,7 +682,8 @@ public void GenerateCode(CodeGenerator output)

if (isConstructor)
{
continue; // in a constructor we don't need to read the vars from storage as they dont exist yet
// don't do anything more, since in a constructor we don't need to read the vars from storage as they dont exist yet
continue;
}

//var fieldKey = SmartContract.GetKeyForField(this.scope.Root.Name, variable.Name, false);
Expand Down
14 changes: 12 additions & 2 deletions Compiler/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ public static LibraryDeclaration LoadLibrary(string name, Scope scope, ModuleKin
libDecl.AddMethod("transfer", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.TransferToken");
libDecl.AddMethod("mint", MethodImplementationType.ExtCall, VarKind.Number, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("to", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("rom", VarKind.Any), new MethodParameter("ram", VarKind.Any), new MethodParameter("seriesID", VarKind.Any) })
.SetParameterCallback("rom", ConvertFieldToBytes).SetParameterCallback("ram", ConvertFieldToBytes).SetAlias("Runtime.MintToken");
libDecl.AddMethod("write", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("address", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("token ID", VarKind.Number), new MethodParameter("ram", VarKind.Any) }).SetParameterCallback("ram", ConvertFieldToBytes).SetAlias("Runtime.WriteToken");
libDecl.AddMethod("write", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("address", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("tokenID", VarKind.Number), new MethodParameter("ram", VarKind.Any) }).SetParameterCallback("ram", ConvertFieldToBytes).SetAlias("Runtime.WriteToken");
libDecl.AddMethod("readROM", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.ReadTokenROM").SetPostCallback(ConvertGenericResult);
libDecl.AddMethod("readRAM", MethodImplementationType.ExtCall, VarType.Generic(0), new[] { new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.ReadTokenRAM").SetPostCallback(ConvertGenericResult);
libDecl.AddMethod("burn", MethodImplementationType.ExtCall, VarKind.None, new[] { new MethodParameter("from", VarKind.Address), new MethodParameter("symbol", VarKind.String), new MethodParameter("id", VarKind.Number) }).SetAlias("Runtime.BurnToken");
Expand Down Expand Up @@ -895,7 +895,17 @@ public void Compile()
DebugInfo temp;
Dictionary<string, int> labels;

script = AssemblerUtils.BuildScript(lines, this.Name, out temp, out labels);

try
{
script = AssemblerUtils.BuildScript(lines, this.Name, out temp, out labels);
}
catch (Exception e)
{
System.IO.File.WriteAllText("output.asm", string.Join('\n', lines));
throw e;
}

this.debugInfo = temp;

lines = AssemblerUtils.CommentOffsets(lines, this.debugInfo).ToArray();
Expand Down
5 changes: 0 additions & 5 deletions Compiler/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,6 @@ static void Main(string[] args)

foreach (var module in modules)
{
/*if (module.Hidden)
{
continue;
}*/

ExportModule(module);

foreach (var subModule in module.SubModules)
Expand Down
Loading

0 comments on commit bc37cfd

Please sign in to comment.