コード例 #1
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        // A map literal.
        private static void Map(Compiler c, bool allowAssignment)
        {
            // Load the Map class.
            int mapClassSymbol = c._parser.Module.Variables.FindIndex(v => v.Name == "Map");
            c.EmitShortArg(Instruction.LoadModuleVar, mapClassSymbol);

            // Instantiate a new map.
            c.CallMethod(0, "<instantiate>");

            // Compile the map elements. Each one is compiled to just invoke the
            // subscript setter on the map.
            if (c.Peek() != TokenType.RightBrace)
            {
                do
                {
                    c.IgnoreNewlines();

                    // Push a copy of the map since the subscript call will consume it.
                    c.Emit(Instruction.Dup);

                    // The key.
                    c.ParsePrecedence(false, Precedence.Primary);
                    c.Consume(TokenType.Colon, "Expect ':' after map key.");

                    // The value.
                    c.Expression();

                    c.CallMethod(2, "[_]=(_)");

                    // Discard the result of the setter call.
                    c.Emit(Instruction.Pop);
                } while (c.Match(TokenType.Comma));
            }

            // Allow newlines before the closing '}'.
            c.IgnoreNewlines();
            c.Consume(TokenType.RightBrace, "Expect '}' after map entries.");
        }
コード例 #2
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        // Compiles a method signature for an infix operator.
        static void InfixSignature(Compiler c, Signature signature)
        {
            // Add the RHS parameter.
            signature.Type = SignatureType.Method;
            signature.Arity = 1;

            // Parse the parameter name.
            c.Consume(TokenType.LeftParen, "Expect '(' after operator name.");
            c.DeclareNamedVariable();
            c.Consume(TokenType.RightParen, "Expect ')' after parameter name.");
        }
コード例 #3
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        // A list literal.
        private static void List(Compiler c, bool allowAssignment)
        {
            // Load the List class.
            int listClassSymbol = c._parser.Module.Variables.FindIndex(v => v.Name == "List");
            //ASSERT(listClassSymbol != -1, "Should have already defined 'List' variable.");
            c.EmitShortArg(Instruction.LoadModuleVar, listClassSymbol);

            // Instantiate a new list.
            c.CallMethod(0, "<instantiate>");

            // Compile the list elements. Each one compiles to a ".add()" call.
            if (c.Peek() != TokenType.RightBracket)
            {
                do
                {
                    c.IgnoreNewlines();

                    // Push a copy of the list since the add() call will consume it.
                    c.Emit(Instruction.Dup);

                    // The element.
                    c.Expression();
                    c.CallMethod(1, "add(_)");

                    // Discard the result of the add() call.
                    c.Emit(Instruction.Pop);
                } while (c.Match(TokenType.Comma));
            }

            // Allow newlines before the closing ']'.
            c.IgnoreNewlines();
            c.Consume(TokenType.RightBracket, "Expect ']' after list elements.");
        }
コード例 #4
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        private static void Conditional(Compiler c, bool allowAssignment)
        {
            // Ignore newline after '?'.
            c.IgnoreNewlines();

            // Jump to the else branch if the condition is false.
            int ifJump = c.EmitJump(Instruction.JumpIf);

            // Compile the then branch.
            c.ParsePrecedence(allowAssignment, Precedence.Ternary);

            c.Consume(TokenType.Colon, "Expect ':' after then branch of conditional operator.");
            c.IgnoreNewlines();

            // Jump over the else branch when the if branch is taken.
            int elseJump = c.EmitJump(Instruction.Jump);

            // Compile the else branch.
            c.PatchJump(ifJump);

            c.ParsePrecedence(allowAssignment, Precedence.Assignment);

            // Patch the jump over the else.
            c.PatchJump(elseJump);
        }
コード例 #5
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
 // A parenthesized expression.
 private static void Grouping(Compiler c, bool allowAssignment)
 {
     c.Expression();
     c.Consume(TokenType.RightParen, "Expect ')' after expression.");
 }
コード例 #6
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        public static ObjFn Compile(SophieVM vm, ObjModule module, string sourcePath, string source, bool printErrors)
        {
            Parser parser = new Parser
            {
                Vm = vm,
                Module = module,
                SourcePath = sourcePath,
                Source = source,
                TokenStart = 0,
                CurrentChar = 0,
                CurrentLine = 1,
                Current = { Type = TokenType.Error, Start = 0, Length = 0, Line = 0 },
                PrintErrors = printErrors,
                HasError = false,
                Raw = ""
            };

            Compiler compiler = new Compiler(parser, null, true);

            // Read the first token.
            compiler.NextToken();

            compiler.IgnoreNewlines();

            while (!compiler.Match(TokenType.Eof))
            {
                compiler.Definition();

                // If there is no newline, it must be the end of the block on the same line.
                if (!compiler.MatchLine())
                {
                    compiler.Consume(TokenType.Eof, "Expect end of file.");
                    break;
                }
            }

            compiler.Emit(Instruction.Null);
            compiler.Emit(Instruction.Return);

            // See if there are any implicitly declared module-level variables that never
            // got an explicit definition.
            // TODO: It would be nice if the error was on the line where it was used.
            for (int i = 0; i < parser.Module.Variables.Count; i++)
            {
                ModuleVariable t = parser.Module.Variables[i];
                if (t.Container == Obj.Undefined)
                {
                    compiler.Error(string.Format("Variable '{0}' is used but not defined.", t.Name));
                }
            }

            return compiler.EndCompiler();
        }
コード例 #7
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
 private static void Call(Compiler c, bool allowAssignment)
 {
     c.IgnoreNewlines();
     c.Consume(TokenType.Name, "Expect method name after '.'.");
     c.NamedCall(allowAssignment, Instruction.Call0);
 }
コード例 #8
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        private static void super_(Compiler c, bool allowAssignment)
        {
            ClassCompiler enclosingClass = c.GetEnclosingClass();

            if (enclosingClass == null)
            {
                c.Error("Cannot use 'super' outside of a method.");
            }
            else if (enclosingClass.IsStaticMethod)
            {
                c.Error("Cannot use 'super' in a static method.");
            }

            c.LoadThis();

            // TODO: Super operator calls.

            // See if it's a named super call, or an unnamed one.
            if (c.Match(TokenType.Dot))
            {
                // Compile the superclass call.
                c.Consume(TokenType.Name, "Expect method name after 'super.'.");
                c.NamedCall(allowAssignment, Instruction.Super0);
            }
            else if (enclosingClass != null)
            {
                // No explicit name, so use the name of the enclosing method. Make sure we
                // check that enclosingClass isn't null first. We've already reported the
                // error, but we don't want to crash here.
                c.MethodCall(Instruction.Super0, enclosingClass.MethodName, enclosingClass.MethodLength);
            }
        }
コード例 #9
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        // Compiles a method signature for a subscript operator.
        private static void SubscriptSignature(Compiler c, Signature signature)
        {
            signature.Type = SignatureType.Subscript;

            // The signature currently has "[" as its name since that was the token that
            // matched it. Clear that out.
            signature.Length = 0;
            signature.Name = "";

            // Parse the parameters inside the subscript.
            c.FinishParameterList(signature);
            c.Consume(TokenType.RightBracket, "Expect ']' after parameters.");

            c.MaybeSetter(signature);
        }
コード例 #10
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        // Subscript or "array indexing" operator like `foo[bar]`.
        private static void Subscript(Compiler c, bool allowAssignment)
        {
            Signature signature = new Signature { Name = "", Length = 0, Type = SignatureType.Subscript, Arity = 0 };

            // Parse the argument list.
            c.FinishArgumentList(signature);
            c.Consume(TokenType.RightBracket, "Expect ']' after arguments.");

            if (c.Match(TokenType.Eq))
            {
                if (!allowAssignment) c.Error("Invalid assignment.");

                signature.Type = SignatureType.SubscriptSetter;

                // Compile the assigned value.
                c.ValidateNumParameters(++signature.Arity);
                c.Expression();
            }

            c.CallSignature(Instruction.Call0, signature);
        }
コード例 #11
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        private static void new_(Compiler c, bool allowAssignment)
        {
            // Allow a dotted name after 'new'.
            c.Consume(TokenType.Name, "Expect name after 'new'.");
            Name(c, false);
            while (c.Match(TokenType.Dot))
            {
                Call(c, false);
            }

            // The angle brackets in the name are to ensure users can't call it directly.
            c.CallMethod(0, "<instantiate>");

            // Invoke the constructor on the new instance.
            c.MethodCall(Instruction.Call0, "new", 3);
        }
コード例 #12
0
ファイル: Compiler.cs プロジェクト: robotii/sophielang
        // Compiles a method signature for an operator that can either be unary or
        // infix (i.e. "-").
        private static void MixedSignature(Compiler c, Signature signature)
        {
            signature.Type = SignatureType.Getter;

            // If there is a parameter, it's an infix operator, otherwise it's unary.
            if (c.Match(TokenType.LeftParen))
            {
                // Add the RHS parameter.
                signature.Type = SignatureType.Method;
                signature.Arity = 1;

                // Parse the parameter name.
                c.DeclareNamedVariable();
                c.Consume(TokenType.RightParen, "Expect ')' after parameter name.");
            }
        }