Пример #1
0
        private void SetupOperands(ASTBinary n)
        {
            //push L
            n.Left.Visit(this);

            //push R
            n.Right.Visit(this);
        }
Пример #2
0
        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));
            }
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
        /// <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);
            }
        }
Пример #5
0
        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."));
        }