private void SetupOperands(ASTBinary n) { //push L n.Left.Visit(this); //push R n.Right.Visit(this); }
private void TypeCheckEquality(ASTBinary n) { CFlatType lhs = CheckSubTree(n.Left); CFlatType rhs = CheckSubTree(n.Right); if (lhs.IsSupertype(rhs) || rhs.IsSupertype(lhs)) { //we're good _lastSeenType = n.CFlatType = new TypeBool(); } else { //invalid ReportError(n.Location, "Types '{0}' and '{1}' are not compatible for equality.", TypeToFriendlyName(lhs), TypeToFriendlyName(rhs)); } }
private void TypeCheckBooleanOperator(ASTBinary n, string errorMessage) { bool valid = false; CFlatType lhs = CheckSubTree(n.Left); if (lhs is TypeBool) { CFlatType rhs = CheckSubTree(n.Right); if (rhs is TypeBool) { _lastSeenType = n.CFlatType = new TypeBool(); valid = true; } } if (!valid) { ReportError(n.Location, errorMessage); } }
/// <summary> /// This method looks kinda ugly because I'm using it for all binary operations, which may actually typecheck /// to different types /// </summary> /// <param name="n"></param> /// <param name="errorMessage"></param> /// <param name="resultingType">The type that the expression will evaluate as. This is optional, so if you /// don't pass it in, the compiler will use the supertype of the two operands. /// </param> private void TypeCheckNumericBinary(ASTBinary n, string errorMessage, CFlatType resultingType = null) { bool valid = false; CFlatType lhs = CheckSubTree(n.Left); if (lhs.IsNumeric) { CFlatType rhs = CheckSubTree(n.Right); if (rhs.IsNumeric) { //if the parameter was not passed in, we'll figure it out resultingType = resultingType ?? Supertype(lhs, rhs); n.CFlatType = resultingType; _lastSeenType = resultingType; valid = true; } } if (!valid) { ReportError(n.Location, errorMessage); } }
public string GetCodeForCommand(IASTNode command, float lineNumber) { if (command.Type == ASTNodeType.Command) { var cmd = (ASTCommand)command; switch (cmd.Command) { case "PRINT": return(Target.GetSnippet("commands", "print", "text", GetCodeForExpression(cmd.Operand))); case "CLS": return(Target.GetSnippet("commands", "cls")); case "GOTO": return(Target.GetSnippet("commands", "goto", "lineNumber", GetCodeForExpression(cmd.Operand))); case "GOSUB": return(Target.GetSnippet("commands", "gosub", "lineNumber", GetCodeForExpression(cmd.Operand))); case "RETURN": return(Target.GetSnippet("commands", "return")); case "SLEEP": return(Target.GetSnippet("commands", "sleep", "time", GetCodeForExpression(cmd.Operand))); case "LET": // Operand of LET is a binary expression with = return(GetCodeForExpression(cmd.Operand)); case "NEXT": return(GetCodeForNext((ASTVariable)cmd.Operand)); case "TOPOF": return(GetCodeForTopof((ASTVariable)cmd.Operand)); case "DIM": return(GetCodeForDim((ASTCall)cmd.Operand)); case "LISTADD": return(GetCodeForListAdd((ASTCompoundExpression)cmd.Operand)); case "LISTRM": return(GetCodeForListRm((ASTCompoundExpression)cmd.Operand)); case "LIST": return(GetCodeForList((ASTVariable)cmd.Operand)); // TODO: PRINTAT case "INK": return(Target.GetSnippet("commands", "ink", "colour", GetCodeForExpression(cmd.Operand))); case "PAPER": return(Target.GetSnippet("commands", "paper", "colour", GetCodeForExpression(cmd.Operand))); case "EXIT": return(Target.GetSnippet("commands", "exit")); case "STOP": return(Target.GetSnippet("commands", "stop")); case "WAITKEY": return(Target.GetSnippet("commands", "waitkey")); case "INPUT": return(GetCodeForInput(cmd.Operand)); case "WRITEFILE": return(GetCodeForFileWrite(cmd)); case "APPENDFILE": return(GetCodeForFileWrite(cmd)); default: return(Croak($@" Unsupported command ""{cmd.Command}"" It's a valid command, but not yet implemented in the new transpiler. ")); } } if (command.Type == ASTNodeType.If) { var ifCmd = (ASTIf)command; var thenCode = ""; foreach (var thn in ifCmd.Then) { thenCode += GetCodeForCommand(thn, lineNumber); } var elseCode = ""; if (ifCmd.Else != null) { foreach (var els in ifCmd.Else) { elseCode += GetCodeForCommand(els, lineNumber); } elseCode = Target.GetSnippet("structures", "else", "body", elseCode); } return(Target.GetComplexSnippet("structures", "if", new Dictionary <string, string>() { { "condition", GetCodeForExpression(ifCmd.Condition) }, { "body", thenCode } }) + elseCode); } if (command.Type == ASTNodeType.For) { var forLoop = (ASTFor)command; var loopVar = (ASTVariable)forLoop.Assignment.Left; var counter = GetCodeForVar(loopVar); // Bool for skip reassign, not exposed to user code var forSkip = GetCodeForVar(loopVar, true, false); var skpDecl = $"{forSkip}_skip"; var skp = Target.GetSnippet("vars", "varAccess", "name", skpDecl); declarations += Target.GetSnippet("vars", "boolDeclaration", "name", skpDecl); var startCount = forLoop.Assignment.Right; var condition = new ASTBinary() { Operator = "<=", Left = loopVar, Right = forLoop.ToMax }; var loop = new Loop() { Condition = condition, DefinedOnLine = lineNumber, SkipVar = skp, Start = startCount, Step = forLoop.Step, Counter = loopVar }; loops.Add(counter, loop); return(Target.GetComplexSnippet("loops", "check", new Dictionary <string, string>() { { "skip", skp }, { "loopVar", counter }, { "start", GetCodeForExpression(startCount) } })); } if (command.Type == ASTNodeType.FunctionDefinition) { var fn = (ASTFunctionDefinition)command; var fnName = fn.FunctionName; var fnType = fnName.IsString ? "string" : "number"; var args = new List <string>(); foreach (var arg in fn.Arguments) { var aType = arg.IsString ? "string" : "number"; var vr = GetCodeForVar(arg, false); var aCode = Target.GetSnippet("functions", aType + "Arg", "arg", vr); args.Add(aCode); } var argString = string.Join(Target.GetSnippet("functions", "argSeperator"), args); var fnCode = Target.GetComplexSnippet("functions", fnType + "Declaration", new Dictionary <string, string>() { { "name", GetCodeForVar(fnName, false) }, { "args", argString }, { "exp", GetCodeForExpression(fn.Expression) } }); declarations += fnCode; return(""); } // TODO: A more generic if (isExpression(command)) if (command.Type == ASTNodeType.Call) { var code = GetCodeForCall((ASTCall)command); return(Target.GetSnippet("commands", "expression", "exp", code)); } return(Croak("Unsupported AST Node in new transpiler.")); }