Example #1
0
 void CompileFn(ParseTree ast, Types.Environment env, bool useVal, bool more)
 {
     if (useVal)
     {
         var fn = this.GenLabel("FN");
         var l  = this.GenLabel();
         this.Gen(Instruction.Opcodes.Jump, l);
         this.Gen(Instruction.Opcodes.Label, fn, ast);
         var args = ast.Children.ElementAt(0);
         var body = ast.Children.ElementAt(1);
         this.CompileFnBody(args, body, env);
         this.Gen(Instruction.Opcodes.Label, l);
         var arity            = args.Children.Count();
         var hasCollectParams = args.Children.Any(pt => pt.Label == ParseTree.Labels.CollectName);
         if (hasCollectParams)
         {
             arity--;
             arity += Callable.CollectParamsArityModifier;
         }
         this.Gen(Instruction.Opcodes.Fn, new object[] {
             fn,
             arity
         });
         if (!more)
         {
             this.Gen(Instruction.Opcodes.Return);
         }
     }
 }
Example #2
0
        void ExtendFrame(Types.Environment env, string name, ParseTree nameAst)
        {
            var topFrame           = env.Frame;
            var currentStartPos    = nameAst.StartPos;
            var previousDefinition = topFrame.EntryFor(name);

            if (previousDefinition != null)
            {
                var sourceFile = SourceFile.FindSource(this.sources, previousDefinition.FileName);
                var pos        = Position.CalculatePosition(sourceFile, previousDefinition.StartPos);
                var message    = String.Format(
                    "Variable '{0}' is already defined in this frame in file '{1}', at line {2}, column {3}.",
                    name, pos.FileName, pos.Line, pos.Column);
                this.RaiseError(currentStartPos, nameAst.EndPos, message);
            }
            else
            {
                var newVar = new EnvVar()
                {
                    Name     = name,
                    FileName = this.fileName,
                    Place    = topFrame.Vars.Count,
                    StartPos = currentStartPos
                };
                topFrame.Vars.Add(newVar);
            }
        }
Example #3
0
        void CompileBlock(IEnumerable <ParseTree> ast, Types.Environment env, bool useVal, bool more)
        {
            int?meatStart = PositionOf(ast, pt => pt.Label != ParseTree.Labels.FileName, false);
            int?meatEnd   = PositionOf(ast, pt => pt.Label != ParseTree.Labels.FileName, true);

            IEnumerable <ParseTree> prefixFluff, meat, suffixFluff;

            if (meatStart == null && meatEnd == null)
            {
                prefixFluff = ast;
                meat        = new List <ParseTree> ();
                suffixFluff = new List <ParseTree> ();
            }
            else
            {
                prefixFluff = ast.Take(meatStart.Value);
                meat        = ast.Skip(meatStart.Value).Take(meatEnd.Value - meatStart.Value + 1);
                suffixFluff = ast.Skip(meatEnd.Value + 1);
            }
            foreach (var pt in prefixFluff)
            {
                CompileAst(pt, this.EmptyEnv(), true, true);
            }
            CompileBlockMeat(meat, env, useVal, more);
            foreach (var pt in suffixFluff)
            {
                CompileAst(pt, this.EmptyEnv(), true, true);
            }
        }
Example #4
0
 void CompileIf(ParseTree ast, Types.Environment env, bool useVal, bool more)
 {
     if (more)
     {
         var l1   = this.GenLabel();
         var l2   = this.GenLabel();
         var pred = ast.Children.ElementAt(0);
         this.CompileAst(pred, env, true, true);
         this.Gen(Instruction.Opcodes.Fjump, l1);
         var thenAction = ast.Children.ElementAt(1);
         this.CompileAst(thenAction, env, useVal, true);
         this.Gen(Instruction.Opcodes.Jump, l2);
         this.Gen(Instruction.Opcodes.Label, l1);
         var elseAction = ast.Children.ElementAt(2);
         this.CompileAst(elseAction, env, useVal, true);
         this.Gen(Instruction.Opcodes.Label, l2);
     }
     else
     {
         var l1   = this.GenLabel();
         var pred = ast.Children.ElementAt(0);
         this.CompileAst(pred, env, true, true);
         this.Gen(Instruction.Opcodes.Fjump, l1);
         var thenAction = ast.Children.ElementAt(1);
         this.CompileAst(thenAction, env, useVal, false);
         this.Gen(Instruction.Opcodes.Label, l1);
         var elseAction = ast.Children.ElementAt(2);
         this.CompileAst(elseAction, env, useVal, false);
     }
 }
Example #5
0
        void CompileFuncall(ParseTree ast, Types.Environment env, bool useVal, bool more)
        {
            foreach (var child in ast.Children.Skip(1))
            {
                this.CompileAst(child, env, true, true);
            }
            var funAst = ast.Children.First();
            var compiledAsInstruction = false;

            if (funAst.Label == ParseTree.Labels.Prim0)
            {
                compiledAsInstruction =
                    this.CompiledAsInstruction(funAst, ast.Children.Count() - 1, useVal, more);
            }
            if (!compiledAsInstruction)
            {
                this.CompileAst(funAst, env, true, true);
                if (more)
                {
                    this.Gen(Instruction.Opcodes.Call, ast.Children.Count() - 1, ast);
                    if (!useVal)
                    {
                        this.Gen(Instruction.Opcodes.Pop);
                    }
                }
                else
                {
                    this.Gen(Instruction.Opcodes.CallJ, ast.Children.Count() - 1, ast);
                }
            }
        }
Example #6
0
 void CompileSetVar(string name, Types.Environment env, bool useVal, bool more, ParseTree astForPos)
 {
     this.Gen(
         Instruction.Opcodes.Lset,
         this.FindName(name, env, astForPos.StartPos, astForPos.EndPos),
         astForPos);
     this.FinishInstruction(useVal, more);
 }
Example #7
0
        void CompileName(ParseTree ast, Types.Environment env, bool useVal, bool more)
        {
            var varName = ast.Content;

            this.Gen(Instruction.Opcodes.Lget,
                     this.FindName(varName, env, ast.StartPos, ast.EndPos),
                     ast);
            this.FinishInstruction(useVal, more);
        }
Example #8
0
        void CompileBlockReturn(ParseTree ast, Types.Environment env)
        {
            var blockName = ast.Children.ElementAt(0);
            var result    = ast.Children.ElementAt(1);

            this.CompileAst(blockName, env, true, true);
            this.CompileAst(result, env, true, true);
            this.Gen(Instruction.Opcodes.BlockReturn, null, ast);
        }
Example #9
0
        void CompileVar(ParseTree ast, Types.Environment env, bool useVal, bool more)
        {
            var nameAst = ast.Children.ElementAt(0);
            var name    = nameAst.Content;

            this.ExtendFrame(env, name, nameAst, false);
            this.CompileAst(ast.Children.ElementAt(1), env, true, true);
            this.CompileSetVar(name, env, useVal, more, ast);
        }
Example #10
0
 void CompileStatements(
     Types.Environment env,
     IEnumerable <ParseTree> dropValueAsts, ParseTree valueAst,
     bool more)
 {
     foreach (var ast in dropValueAsts)
     {
         this.CompileAst(ast, env, false, true);
     }
     this.CompileAst(valueAst, env, true, more);
 }
Example #11
0
        void CompileNamedBlock(ParseTree ast, Types.Environment env, bool useVal, bool more)
        {
            var blockName     = ast.Children.ElementAt(0);
            var blockContents = ast.Children.ElementAt(1);
            var blockEnd      = this.GenLabel("BE");

            this.CompileAst(blockName, env, true, true);
            this.Gen(Instruction.Opcodes.Block, blockEnd, ast);
            this.CompileAst(blockContents, env, true, true);
            this.Gen(Instruction.Opcodes.Label, blockEnd);
            this.Gen(Instruction.Opcodes.PopBlock, null, ast);
            this.FinishInstruction(useVal, more);
        }
Example #12
0
 void CompileAtom(ParseTree ast, Types.Environment env, bool useVal, bool more)
 {
     if (useVal)
     {
         this.Gen(
             Instruction.Opcodes.Const,
             this.CompileAtomValue(ast.Label, ast.Content),
             ast);
         if (!more)
         {
             this.Gen(Instruction.Opcodes.Return);
         }
     }
 }
Example #13
0
 void CompileBlockMeat(IEnumerable <ParseTree> ast, Types.Environment env, bool useVal, bool more)
 {
     if (ast.Count() > 0)
     {
         var newVars        = ast.Where(child => child.Label == ParseTree.Labels.Var);
         var newVarCount    = newVars.Count();
         var dropValueCount = ast.Count() - 1;
         var dropValueAsts  = ast.Take(dropValueCount);
         var valueAst       = ast.Skip(dropValueCount).First();
         var newEnv         = this.EmptyEnv();
         newEnv.Next = env;
         if (newVarCount > 0)
         {
             var newVarNames = newVars
                               .Select(child => child.Children.ElementAt(0).Content).ToArray();
             this.Gen(
                 Instruction.Opcodes.NewFrame, newVarNames,
                 startPos: newVars.First().StartPos,
                 endPos: newVars.Last().EndPos);
             foreach (var varName in newVarNames)
             {
                 this.ExtendFrame(newEnv, varName, null, true);
             }
             this.CompileStatements(newEnv, dropValueAsts, valueAst, more);
             if (more)
             {
                 this.Gen(Instruction.Opcodes.DropFrame);
             }
             if (!useVal)
             {
                 this.Gen(Instruction.Opcodes.Pop);
             }
         }
         else
         {
             this.CompileStatements(env, dropValueAsts, valueAst, more);
             if (!useVal)
             {
                 this.Gen(Instruction.Opcodes.Pop);
             }
         }
     }
     else
     {
         this.Gen(Instruction.Opcodes.Const, Value.Make());
         FinishInstruction(useVal, more);
     }
 }
Example #14
0
        void CompileSet(ParseTree ast, Types.Environment env, bool useVal, bool more)
        {
            var leftHandSide = ast.Children.First();

            if (leftHandSide.Label == ParseTree.Labels.Name)
            {
                this.CompileAst(ast.Children.ElementAt(2), env, true, true);
                this.CompileSetVar(leftHandSide.Content, env, useVal, more, ast);
            }
            else
            {
                if (!this.IsGrefCall(leftHandSide))
                {
                    this.RaiseError(
                        ast.StartPos, ast.EndPos,
                        "Assignment only supported for names, arrays and hashes.");
                }
                var arrayOrHash        = leftHandSide.Children.ElementAt(1);
                var index              = leftHandSide.Children.ElementAt(2);
                var literalStringIndex = index.Label == ParseTree.Labels.String;
                var setOperator        = leftHandSide.Children.ElementAt(0);
                var primitiveParseTree = new ParseTree()
                {
                    Label    = ParseTree.Labels.Prim0,
                    StartPos = setOperator.StartPos,
                    EndPos   = setOperator.EndPos,
                    Content  = literalStringIndex ? "svm_set_dot_indexed" : "svm_set_indexed"
                };
                var rightHandSide = ast.Children.ElementAt(2);
                var callParseTree = new ParseTree()
                {
                    Label    = ParseTree.Labels.Call,
                    StartPos = ast.StartPos,
                    EndPos   = ast.EndPos,
                    Children = new ParseTree[] {
                        primitiveParseTree,
                        arrayOrHash,
                        index,
                        rightHandSide
                    }
                };
                this.CompileAst(callParseTree, env, useVal, more);
            }
        }
Example #15
0
 int[] FindName(string varName, Types.Environment env, int startPos, int endPos, int frameNumber = 0)
 {
     if (env == null)
     {
         var message = String.Format("Undefined variable '{0}'.", varName);
         this.RaiseError(startPos, endPos, message);
         return(null);
     }
     else
     {
         for (var j = 0; j < env.Frame.Vars.Count; j++)
         {
             if (varName == env.Frame.Vars [j].Name)
             {
                 return(new int[] { frameNumber, j });
             }
         }
         return(FindName(varName, env.Next, startPos, endPos, frameNumber + 1));
     }
 }
Example #16
0
 void CompileFn(ParseTree ast, Types.Environment env, bool useVal, bool more)
 {
     if (useVal)
     {
         var fn = this.GenLabel("FN");
         var l  = this.GenLabel();
         this.Gen(Instruction.Opcodes.Jump, l);
         this.Gen(Instruction.Opcodes.Label, fn, ast);
         var args = ast.Children.ElementAt(0);
         var body = ast.Children.ElementAt(1);
         this.CompileFnBody(args, body, env);
         this.Gen(Instruction.Opcodes.Label, l);
         this.Gen(Instruction.Opcodes.Fn, new object[] {
             fn,
             args.Children.Count()
         }
                  );
         if (!more)
         {
             this.Gen(Instruction.Opcodes.Return);
         }
     }
 }
Example #17
0
 void CompileFnBody(ParseTree args, ParseTree body, Types.Environment env)
 {
     if (args.Children.Count() > 0)
     {
         var newEnv = this.EmptyEnv();
         newEnv.Next = env;
         foreach (var arg in args.Children)
         {
             this.ExtendFrame(newEnv, arg.Content, arg, false);
         }
         var varNames = args.Children.Select(arg => arg.Content).ToArray();
         this.Gen(
             Instruction.Opcodes.NewFrame, varNames,
             startPos: args.Children.First().StartPos,
             endPos: args.Children.Last().EndPos);
         this.Gen(Instruction.Opcodes.Args, varNames.Length);
         this.CompileAst(body, newEnv, true, false);
     }
     else
     {
         this.CompileAst(body, env, true, false);
     }
 }
Example #18
0
        void CompileAst(ParseTree ast, Types.Environment env, bool useVal, bool more)
        {
            switch (ast.Label)
            {
            case ParseTree.Labels.FileName:
                this.fileName = ast.Content;
                this.Gen(Instruction.Opcodes.FileName, this.fileName);
                break;

            case ParseTree.Labels.Var:
                this.CompileVar(ast, env, useVal, more);
                break;

            case ParseTree.Labels.Fn:
                this.CompileFn(ast, env, useVal, more);
                break;

            case ParseTree.Labels.Begin:
                this.CompileBlock(ast.Children, env, useVal, more);
                break;

            case ParseTree.Labels.Assignment:
                this.CompileSet(ast, env, useVal, more);
                break;

            case ParseTree.Labels.If:
                this.CompileIf(ast, env, useVal, more);
                break;

            case ParseTree.Labels.Name:
                this.CompileName(ast, env, useVal, more);
                break;

            case ParseTree.Labels.Call:
                this.CompileFuncall(ast, env, useVal, more);
                break;

            case ParseTree.Labels.Prim0:
                this.CompilePrim0(ast, useVal, more);
                break;

            case ParseTree.Labels.UserDefinedPrimitive:
                this.CompileUserDefinedPrimitive(ast, useVal, more);
                break;

            case ParseTree.Labels.Number:
                this.CompileAtom(ast, env, useVal, more);
                break;

            case ParseTree.Labels.String:
                this.CompileAtom(ast, env, useVal, more);
                break;

            case ParseTree.Labels.Bool:
                this.CompileAtom(ast, env, useVal, more);
                break;

            case ParseTree.Labels.Void:
                this.CompileAtom(ast, env, useVal, more);
                break;

            case ParseTree.Labels.NamedBlock:
                this.CompileNamedBlock(ast, env, useVal, more);
                break;

            case ParseTree.Labels.BlockReturn:
                this.CompileBlockReturn(ast, env);
                break;

            case ParseTree.Labels.Context:
                this.CompileContext(ast, useVal, more);
                break;

            case ParseTree.Labels.Placeholder:
                RaiseError(ast.StartPos, ast.EndPos, "'$' without '->'.");
                break;

            default:
                Utils.Panic();
                break;
            }
        }