Ejemplo n.º 1
0
        public void EmitDecl(TranspilerStream stream)
        {
            // If this is the global block, don't allow statements.
            if (Parent == null && Stmts.Count > 0)
            {
                throw new CompileError(Stmts.First().Token,
                                       $"Statements not allowed in the global block");
            }

            var typeDeclIds = new HashSet <string>();

            foreach (var decl in TypeDecls)
            {
                typeDeclIds.Add(decl.Id.Text);
                decl.EmitForwardDecl(stream);
            }

            // Some metafunctions should be emitted within the type declaration
            // itself. Emit those now.
            if (ParentDecl is TypeDecl)
            {
                foreach (var stmt in Stmts)
                {
                    if (stmt is ExprStmt expr)
                    {
                        if (expr.Expr is FnCall call)
                        {
                            Metafunctions.Emit(stream, call, forward: true);
                        }
                    }
                }
            }

            foreach (var decl in TypeDecls)
            {
                decl.EmitDecl(stream);
            }

            foreach (var decl in FnDecls)
            {
                if (typeDeclIds.Contains(decl.Id.Text) && !decl.IsGeneratedConstructor)
                {
                    throw new CompileError(decl.Id,
                                           $"Type already declared in this scope with ID '{decl.Id.Text}'");
                }

                decl.EmitForwardDecl(stream);
            }
        }
Ejemplo n.º 2
0
        public override void Emit(TranspilerStream stream)
        {
            if (Id.Text.StartsWith('#'))
            {
                Metafunctions.Emit(stream, this, forward: false);
            }
            else
            {
                // Try to find a matching function:
                FnDecl?fn = null;
                if (ParentAccess != null)
                {
                    fn = ParentAccess.Left.TypeDecl.Block.FindFn(this);
                }
                else
                {
                    fn = Block.FindFn(this);
                }
                fn = fn ?? throw new CompileError(Token, "Cannot find matching function");

                // Verify that the expressions passed into the function
                // match the pass-by-tyep of each argument.
                for (int i = 0; i < fn.Params.Count; i++)
                {
                    var param = fn.Params[i];
                    var arg   = Args[i];
                    if (!param.CompatibleWith(arg, out var errorMessage))
                    {
                        throw new CompileError(arg.Token, errorMessage);
                    }
                }

                stream.Write(Compiler.Prefix);
                stream.Write(Id.Text);
                // Functions also have suffixes relating to return type:
                stream.Write("__");
                fn.ReturnType?.Emit(stream);

                // Write function arguments:
                stream.Write('(');

                var actualArgs = new Expr[Args.Count];

                // Process as named args to get a new order of arguments to pass in.
                var namedArgsStarted = false;
                var index            = 0;
                var namedArgs        = new HashSet <string>();
                foreach (var arg in Args)
                {
                    if (arg.NamedArg.HasValue)
                    {
                        namedArgsStarted = true;

                        if (!namedArgs.Add(arg.NamedArg.Value.Text))
                        {
                            throw new CompileError("Named argument already specified");
                        }

                        // Find the matching named parameter.
                        var paramIndex = fn.Params.FindIndex(
                            x => x.Id.Text == arg.NamedArg.Value.Text);

                        if (paramIndex == -1)
                        {
                            throw new CompileError("Named argument not found");
                        }
                        else
                        {
                            if (actualArgs[paramIndex] != null)
                            {
                                throw new CompileError("Argument already specified");
                            }
                            actualArgs[paramIndex] = arg;
                        }
                    }
                    else
                    {
                        if (namedArgsStarted)
                        {
                            throw new CompileError(
                                      "Positional arguments cannot follow named arguments");
                        }

                        actualArgs[index] = arg;
                        index            += 1;
                    }
                }

                // Check for missing arguments.
                if (actualArgs.Any(x => x == null))
                {
                    throw new CompileError("Missing one or more required arguments");
                }

                // Process the generated array of positional args.
                var firstArg = true;
                foreach (var arg in actualArgs)
                {
                    if (!firstArg)
                    {
                        stream.Write(',');
                    }
                    else
                    {
                        firstArg = false;
                    }



                    arg.Emit(stream);
                }

                stream.Write(")");
            }
        }