Beispiel #1
0
 public FunctionInfo(SynFuncDecl function, int typeIndex, bool imported)
 {
     this.function      = function;
     this.typeIndex     = typeIndex;
     this.functionIndex = uint.MaxValue; // Calculated later
     this.imported      = imported;
 }
Beispiel #2
0
        public override void BreakApartParsedTokens()
        {
            SynLog.Log($"Breaking apart type {this.typeName}.");
            SynLog.LogFragments(this.declarationTokens);

            // For struct structname { ... }, remove everything except the ...
            this.declarationTokens.RemoveRange(0, 3);

            int lastIdx = this.declarationTokens.Count - 1;

            if (this.declarationTokens[lastIdx].MatchesSymbol(";"))
            {
                this.declarationTokens.RemoveRange(lastIdx - 1, 2);
            }
            else
            {
                this.declarationTokens.RemoveRange(lastIdx, 1);
            }

            while (this.declarationTokens.Count > 0)
            {
                if (this.declarationTokens[0].MatchesSymbol(";") == true)
                {
                    this.declarationTokens.RemoveAt(0);
                    continue;
                }

                SynRegion rgn = SynRegion.Parse(this, this.declarationTokens);
                if (rgn != null)
                {
                    this.regions.Add(rgn.name, rgn);
                    continue;
                }

                SynFuncDecl fnParse =
                    SynFuncDecl.Parse(
                        this,
                        this.declarationTokens,
                        this.typeName,
                        false,
                        SynFuncDecl.ParseType.StructContext);

                if (fnParse != null)
                {
                    this.AddFunction(fnParse);
                    continue;
                }

                SynVarValue varParse = SynVarValue.ParseBodyVar(this.declarationTokens, SynVarValue.OuterScope.Struct);
                if (varParse != null)
                {
                    this.AddVariable(varParse);
                    continue;
                }
            }
        }
Beispiel #3
0
        public uint?GetFunctionIndex(SynFuncDecl fn)
        {
            FunctionInfo fi;

            if (this.functionLookup.TryGetValue(fn, out fi) == false)
            {
                return(null);
            }

            return(fi.functionIndex);
        }
Beispiel #4
0
        public void RegisterFunction(SynFuncDecl fn)
        {
            SynLog.Log($"Registering function {fn.functionName}.");

            if (this.functionLookup.ContainsKey(fn) == true)
            {
                throw new SynthExceptionImpossible("");
            }

            // Register the type, and get the type index
            FunctionType fty = TurnFnTypeIntoWASMType(fn);

            FunctionInfo finfo = new FunctionInfo(fn, fty.index, fn.isExtern);

            this.functionInfos.Add(finfo);
            this.functionLookup.Add(fn, finfo);
        }
Beispiel #5
0
        public FunctionType TurnFnTypeIntoWASMType(SynFuncDecl fnd)
        {
            WASM.Bin.TypeID        retTy   = GetTrueParamReturnType(fnd.returnType);
            List <WASM.Bin.TypeID> paramTy = new List <WASM.Bin.TypeID>();

            for (int i = 0; i < fnd.parameterSet.Count; ++i)
            {
                paramTy.Add(GetTrueParamReturnType(fnd.parameterSet.Get(i).type));
            }

            for (int i = 0; i < this.functionTypes.Count; ++i)
            {
                FunctionType ftCanid = this.functionTypes[i];
                if (ftCanid.retTy != retTy)
                {
                    continue;
                }

                if (paramTy.Count != ftCanid.paramTys.Count)
                {
                    continue;
                }

                bool match = true;
                for (int j = 0; j < paramTy.Count; ++j)
                {
                    if (paramTy[j] != ftCanid.paramTys[j])
                    {
                        match = false;
                        break;
                    }
                }
                if (match == true)
                {
                    return(ftCanid);
                }
            }

            FunctionType fnNew = new FunctionType(this.functionTypes.Count, retTy, paramTy);

            this.functionTypes.Add(fnNew);

            return(fnNew);
        }
Beispiel #6
0
        public override void BreakApartParsedTokens()
        {
            List <Token> inner = this.declPhrase.GetRange(bodyStart + 1, this.declPhrase.Count - bodyStart - 2);
            int          line  = inner[0].line;

            SynFuncDecl decl =
                SynFuncDecl.Parse(
                    this,
                    inner,
                    null,
                    false,
                    SynFuncDecl.ParseType.Region | SynFuncDecl.ParseType.Externable);

            if (decl == null)
            {
                throw new SynthExceptionSyntax(line, "Only entry and exit functions are allowed in regions.");
            }

            if (string.IsNullOrEmpty(decl.returnTyName) == false)
            {
                throw new SynthExceptionSyntax(line, "Region functions cannot have return types.");
            }

            if (decl.functionName == "entry")
            {
                if (this.entry != null)
                {
                    throw new SynthExceptionSyntax(line, "A region entry function being redeclared.");
                }

                this.entry = decl;
            }
            else if (decl.functionName == "exit")
            {
                if (this.exit != null)
                {
                    throw new SynthExceptionSyntax(line, "A region entry function being redeclared.");
                }

                // TODO: Compare exit parameters with entry.
                this.exit = decl;
            }
        }
Beispiel #7
0
        public void AddFunction(SynFuncDecl fnAdding)
        {
            List <SynFuncDecl> fns;

            if (this.functions.TryGetValue(fnAdding.functionName, out fns) == false)
            {
                fns = new List <SynFuncDecl>();
                this.functions.Add(fnAdding.functionName, fns);
            }
            else
            {
                if (fnAdding.isDestructor == true)
                {
                    foreach (SynFuncDecl already in fns)
                    {
                        if (already.isDestructor == true)
                        {
                            throw new SynthExceptionSyntax(fnAdding.declPhrase[0], "Attempting to declare multiple destructors.");
                        }
                    }
                }
                else
                {
                    // Check if there's a signature collision with function overloads
                    foreach (SynFuncDecl already in fns)
                    {
                        if (already.parameterSet.ExactlyMatches(fnAdding.parameterSet) == true)
                        {
                            throw new System.Exception($"Function declaration {fnAdding.functionName} already included");
                        }
                    }
                }
            }

            fns.Add(fnAdding);
        }
Beispiel #8
0
        // TODO: Perhaps this function should be moved into WASMBuild?
        public SynNestingBuilder BuildFunction(SynFuncDecl fnd)
        {
            SynNestingBuilder builder = new SynNestingBuilder(null);

            if (fnd.ast != null)
            {
                throw new SynthExceptionImpossible($"Attempting to build function {fnd.functionName} AST multiple times.");
            }

            SynLog.Log($"Entered SynthFuncDecl.Build() for {fnd.functionName}.");

            // NOTE: For now functions are non-typed (in the SynthSyn language) and
            // are non addressable.
            fnd.ast =
                new AST(
                    fnd.declPhrase[0],
                    builder,
                    ASTOp.FunctionDecl,
                    fnd,
                    null,
                    false,
                    AST.DataManifest.NoData);

            SynLog.Log($"Building function AST for {fnd.functionName}.");
            SynLog.Log("");

            List <SynNestingBuilder> builders = new List <SynNestingBuilder>();

            builders.Add(builder);

            //List<TokenTree> treeLines = new List<TokenTree>();
            for (int i = 0; i < fnd.executingLines.Count; ++i)
            {
                List <Token> execLine = fnd.executingLines[i];
                SynLog.LogFragments(execLine);

                TokenTree rootLineNode = TokenTree.EatTokensIntoTree(execLine, fnd, true);

                SynLog.LogTree(rootLineNode);

                // If it's a member function (not a static function) then full in the struct
                // we belong to as a he invoking scope. Or else set it to null. Its syntax scope
                // it still all the way where the source code is, but doesn't have a "this" member
                // function.
                SynScope invokingScope = null;
                if (fnd.isStatic == false)
                {
                    invokingScope = fnd.GetStructScope();
                }

                AST exprAST = builder.ProcessFunctionExpression(builders, this, invokingScope, fnd, rootLineNode);
                if (exprAST == null)
                {
                    // We shouldn't have received null, we should have thrown before this
                    throw new SynthExceptionImpossible(""); //TODO:
                }
                fnd.ast.branches.Add(exprAST);
            }
            fnd.ast.branches.Add(new AST(new Token(), builder, ASTOp.EndScope, builder, null, false, AST.DataManifest.NoData));

            SynLog.Log("");
            SynLog.Log($"Encountered {builders.Count} nested scopes.");
            for (int i = 0; i < builders.Count; ++i)
            {
                SynLog.LogIndent(0, $"Scope {i}");
                SynLog.LogIndent(1, $"Line number : {builders[i].lineNumber}");
                SynLog.LogIndent(1, $"Stack Elements : Ele {builders[i].locStkEle.Count} - Vars {builders[i].locStkVars.Count}");
                SynLog.LogIndent(1, $"Memory Stack : Vars {builders[i].memStkVars.Count}");
                SynLog.LogIndent(1, $"Total Memory Stack : Bytes {builders[i].totalMemoryStackBytes}");
            }

            SynLog.Log("");
            SynLog.Log(fnd.ast.DumpDiagnostic());

            SynLog.Log($"Finished building AST : {fnd.functionName}.");
            SynLog.Log($"Converting AST to binary WASM : {fnd.functionName}.");

            // Before the AST is turned into actual WASM binary, we need to finalize the
            // byte alignment and the indices of local stack variables. This is done with
            // CompileAlignment, who's lower scopes should appear earlier in the builders
            // list before higher children scopes.
            for (int i = 0; i < builders.Count; ++i)
            {
                if (i == 0)
                {
                    builders[i].CompileAlignment(fnd);
                }
                else
                {
                    builders[i].CompileAlignment();
                }
            }

            // Gather all the local variables and declare them. This isn't as efficient as things
            // could be because after variables go out of scope, their positions on the stack
            // can be reused if they match types we encounter in the future, but that can be
            // handled later.

            // The program binary
            WASMByteBuilder fnBuild = new WASMByteBuilder();

            // Gather all the local variables
            List <WASM.Bin.TypeID> localVarTys = new List <WASM.Bin.TypeID>();

            foreach (SynNestingBuilder b in builders)
            {
                foreach (ValueRef stkVal in b.locStkEle)
                {
                    if (stkVal.varType.intrinsic == false)
                    {
                        throw new SynthExceptionCompile(""); // TODO: Error msg
                    }
                    switch (stkVal.varType.typeName)
                    {
                    case "bool":
                    case "int8":
                    case "uint8":
                    case "int16":
                    case "uint16":
                    case "int":
                    case "int32":
                        localVarTys.Add(WASM.Bin.TypeID.Int32);
                        break;

                    case "int64":
                    case "uint64":
                        localVarTys.Add(WASM.Bin.TypeID.Int64);
                        break;

                    case "float":
                        localVarTys.Add(WASM.Bin.TypeID.Float32);
                        break;

                    case "double":
                        localVarTys.Add(WASM.Bin.TypeID.Float64);
                        break;
                    }
                }
            }

            List <KeyValuePair <WASM.Bin.TypeID, int> > consolidatedLocalTys = new List <KeyValuePair <WASM.Bin.TypeID, int> >();

            for (int i = 0; i < localVarTys.Count; ++i)
            {
                WASM.Bin.TypeID tyid = localVarTys[i];
                int             ct   = 1;
                ++i;

                for (; i < localVarTys.Count; ++i)
                {
                    if (localVarTys[i] != tyid)
                    {
                        break;
                    }

                    ++ct;
                }
                consolidatedLocalTys.Add(new KeyValuePair <WASM.Bin.TypeID, int>(tyid, ct));
            }

            fnBuild.AddLEB128((uint)consolidatedLocalTys.Count); // Local decl
            for (int i = 0; i < consolidatedLocalTys.Count; ++i)
            {
                fnBuild.AddLEB128((uint)consolidatedLocalTys[i].Value);

                // These are really bytes, but they'll end up being added as bytes since they're
                // small constants
                fnBuild.AddLEB128((uint)consolidatedLocalTys[i].Key);
            }

            builder.BuildBSFunction(fnd, fnd.ast, this, builder, fnBuild);
            fnBuild.Add_End();
            fnd.fnBin = fnBuild.Bin();

            SynLog.Log($"Exiting SynthFuncDecl.Build({fnd.functionName}).");
            return(builder);
        }
Beispiel #9
0
        public byte[] BuildWASM()
        {
            SynLog.LogHeader("Entered BuildWASM() from SynthContext.cs");

            //WASMBuild build = new WASMBuild(this);

            // Gather all the functions in the entire build, and make a collection
            // of their unique types.
            this.rootContext.GatherFunctionRegistration(this);
            // Reorganize function indices so imported functions come first. This is
            // required for WASM.
            this.RealignFunctions();

            List <byte> fileContent = new List <byte>();

            fileContent.AddRange(System.BitConverter.GetBytes(WASM.BinParse.WASM_BINARY_MAGIC));
            fileContent.AddRange(System.BitConverter.GetBytes(1));

            // TODO: Consider removing the WASMSection class (in another file)


            foreach (FunctionInfo fi in this.functionInfos)
            {
                if (fi.function.isExtern == true)
                {
                    continue;
                }

                this.BuildFunction(fi.function);
            }
            //foreach (var kvp in this.rootContext.Functions)
            //{
            //    List<SynthFuncDecl> lst = kvp.Value;
            //    foreach (SynthFuncDecl sfd in lst)
            //    {
            //        if (sfd.isExtern == true)
            //            continue;
            //
            //        this.BuildFunction(sfd);
            //    }
            //}

            //
            //      FUNCTION TYPE DECLARATIONS
            //      "Type"s
            //////////////////////////////////////////////////

            int startFnType = this.GetOrAddFunctionType(WASM.Bin.TypeID.Result, new List <WASM.Bin.TypeID>());

            fileContent.Add((byte)WASM.Bin.Section.TypeSec);
            {
                List <byte> typeSection = new List <byte>();

                // Function type count
                // + 1 for the start function
                typeSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)functionTypes.Count));

                for (int i = 0; i < this.functionTypes.Count; ++i)
                {
                    FunctionType fty = functionTypes[i];

                    // Function tag
                    typeSection.Add((byte)WASM.Bin.TypeID.Function);

                    // Param count
                    typeSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)fty.paramTys.Count));
                    // Param values
                    for (int j = 0; j < fty.paramTys.Count; ++j)
                    {
                        // Types will never be big enough to need LEB encoding. Single byte is fine.
                        typeSection.Add((byte)fty.paramTys[j]);
                    }

                    // Only 1 return value max will ever be returned.
                    if (fty.retTy == WASM.Bin.TypeID.Empty)
                    {
                        typeSection.Add(0);
                    }
                    else
                    {
                        typeSection.Add(1);
                        typeSection.Add((byte)fty.retTy);
                    }
                }

                fileContent.AddRange(WASM.BinParse.EncodeSignedLEB(typeSection.Count));
                fileContent.AddRange(typeSection);
            }

            //
            //      IMPORTED FUNCTION DECLARATIONS
            //      "Import"s
            //////////////////////////////////////////////////
            fileContent.Add((byte)WASM.Bin.Section.ImportSec);
            {
                List <byte> importSection = new List <byte>();

                List <FunctionInfo> lstImported = GetRangeImportFunctions();

                // Function count
                importSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)lstImported.Count));

                for (int i = 0; i < lstImported.Count; ++i)
                {
                    string env   = "ImportedFns";
                    string field = lstImported[i].function.functionName;

                    importSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)env.Length));
                    importSection.AddRange(System.Text.Encoding.ASCII.GetBytes(env));
                    //
                    importSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)field.Length));
                    importSection.AddRange(System.Text.Encoding.ASCII.GetBytes(field));

                    importSection.Add(0); // Import kind

                    importSection.AddRange(WASM.BinParse.EncodeSignedLEB((uint)lstImported[i].typeIndex));
                }

                fileContent.AddRange(WASM.BinParse.EncodeSignedLEB(importSection.Count));
                fileContent.AddRange(importSection);
            }

            //
            //      LOCAL FUNCTION DECLARACTIONS
            //      "Function"s
            //////////////////////////////////////////////////
            List <FunctionInfo> lstLocalFns = GetRangeNonImportFunctions();

            fileContent.Add((byte)PxPre.WASM.Bin.Section.FunctionSec);
            {
                List <byte> functionSection = new List <byte>();

                // Function Count
                functionSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)lstLocalFns.Count + 1));

                for (int i = 0; i < lstLocalFns.Count; ++i)
                {
                    functionSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)lstLocalFns[i].typeIndex));
                }

                functionSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)startFnType));

                fileContent.AddRange(WASM.BinParse.EncodeSignedLEB(functionSection.Count));
                fileContent.AddRange(functionSection);
            }

            int startIdx = -1; // The start index function

            startIdx = functionInfos.Count;

            //
            //      TABLE DECLARACTIONS
            //      "Table"s
            //////////////////////////////////////////////////
            fileContent.Add((byte)WASM.Bin.Section.TableSec);
            {
                List <byte> tableSections = new List <byte>();

                tableSections.AddRange(WASM.BinParse.EncodeUnsignedLEB(0));

                fileContent.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)tableSections.Count));
                fileContent.AddRange(tableSections);
            }

            //
            //      MEMORY DECLARACTIONS
            //      "Memory"s
            //////////////////////////////////////////////////
            fileContent.Add((byte)WASM.Bin.Section.MemorySec);
            {
                List <byte> memorySection = new List <byte>();

                memorySection.AddRange(WASM.BinParse.EncodeUnsignedLEB(1));
                memorySection.Add(0); // flags
                memorySection.Add(2); // initial page ct


                fileContent.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)memorySection.Count));
                fileContent.AddRange(memorySection);
            }

            //
            //      --
            //      "Globals"s
            //////////////////////////////////////////////////
            fileContent.Add((byte)WASM.Bin.Section.GlobalSec);
            {
                List <byte> globalsSection = new List <byte>();

                globalsSection.AddRange(WASM.BinParse.EncodeUnsignedLEB(1));
                //
                globalsSection.Add((byte)WASM.Bin.TypeID.Int32); // Type
                globalsSection.Add(0);                           // Not mutable
                globalsSection.Add((byte)WASM.Instruction.i32_const);
                globalsSection.AddRange(WASM.BinParse.EncodeSignedLEB(stackMemByteCt));
                globalsSection.Add((byte)WASM.Instruction.end);

                fileContent.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)globalsSection.Count));
                fileContent.AddRange(globalsSection);
            }

            //      --
            //      "Export"s
            //////////////////////////////////////////////////
            fileContent.Add((byte)WASM.Bin.Section.ExportSec);
            {
                List <byte> exportSection = new List <byte>();

                uint exportedCt = 0;
                for (int i = 0; i < lstLocalFns.Count; ++i)
                {
                    if (lstLocalFns[i].function.isStatic == false || lstLocalFns[i].function.isEntry == false)
                    {
                        continue;
                    }

                    ++exportedCt;
                }

                ++exportedCt; // +1 for global MemStkSize
                exportSection.AddRange(WASM.BinParse.EncodeUnsignedLEB(exportedCt));

                // Iterate through it again the same way, but actually save out instead of count this time.
                for (int i = 0; i < lstLocalFns.Count; ++i)
                {
                    if (lstLocalFns[i].function.isStatic == false || lstLocalFns[i].function.isEntry == false)
                    {
                        continue;
                    }

                    exportSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)lstLocalFns[i].function.functionName.Length));
                    exportSection.AddRange(System.Text.Encoding.ASCII.GetBytes(lstLocalFns[i].function.functionName));
                    exportSection.Add(0); // kind
                    exportSection.AddRange(WASM.BinParse.EncodeUnsignedLEB(lstLocalFns[i].functionIndex));
                }

                // Add export of MemStkSize
                exportSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)"MemStkSize".Length));
                exportSection.AddRange(System.Text.Encoding.ASCII.GetBytes("MemStkSize"));
                exportSection.Add(3); // kind - TODO: Does PreWASM have this defined somewhere?
                exportSection.Add(0); // Global index

                fileContent.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)exportSection.Count));
                fileContent.AddRange(exportSection);
            }

            //
            //      --
            //      "Start"
            //////////////////////////////////////////////////
            fileContent.Add((byte)WASM.Bin.Section.StartSec);
            {
                List <byte> startSection = new List <byte>();

                startSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)startIdx));


                fileContent.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)startSection.Count));
                fileContent.AddRange(startSection);
            }

            //
            //      --
            //      "Elems"
            //////////////////////////////////////////////////
            fileContent.Add((byte)WASM.Bin.Section.ElementSec);
            {
                List <byte> elemsSection = new List <byte>();

                elemsSection.AddRange(WASM.BinParse.EncodeUnsignedLEB(0));

                fileContent.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)elemsSection.Count));
                fileContent.AddRange(elemsSection);
            }

            //
            //      --
            //      "Code"
            //////////////////////////////////////////////////
            fileContent.Add((byte)WASM.Bin.Section.CodeSec);
            {
                List <byte> codeSection = new List <byte>();

                // Num functions
                codeSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)lstLocalFns.Count + 1));

                for (int i = 0; i < lstLocalFns.Count; ++i)
                {
                    FunctionInfo finfo = lstLocalFns[i];
                    SynFuncDecl  fn    = finfo.function;

                    if (fn.fnBin == null)
                    {
                        throw new SynthExceptionImpossible($"Attempting to save out WASM of function {fn.functionName} that hasn't been processed.");
                    }

                    // Function size
                    codeSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)fn.fnBin.Length));
                    // Locals byte size
                    codeSection.AddRange(fn.fnBin);
                }

                WASMByteBuilder startFn = new WASMByteBuilder();
                startFn.AddLEB128(0); // Local declarations
                // Set the starting stack position (4) in memory. This is basically the stack position, but
                // we reserve the first 4 bytes for the stack information.
                startFn.Add_I32Const(0);
                startFn.Add_I32Const(4);
                startFn.Add_I32Store();
                startFn.Add_End();
                //
                codeSection.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)startFn.BinCount()));
                codeSection.AddRange(startFn.Bin());

                fileContent.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)codeSection.Count));
                fileContent.AddRange(codeSection);
            }

            //
            //      --
            //      "Data"
            //////////////////////////////////////////////////
            fileContent.Add((byte)WASM.Bin.Section.DataSec);
            {
                List <byte> dataSection = new List <byte>();

                dataSection.AddRange(WASM.BinParse.EncodeUnsignedLEB(0));

                fileContent.AddRange(WASM.BinParse.EncodeUnsignedLEB((uint)dataSection.Count));
                fileContent.AddRange(dataSection);
            }

            return(fileContent.ToArray());
        }
Beispiel #10
0
 public int IndexFnTypeIntoWASMType(SynFuncDecl fnd)
 {
     return(TurnFnTypeIntoWASMType(fnd).index);
 }
Beispiel #11
0
        /// <summary>
        /// This function is expected to be called during AST construction
        /// (of whatever needs the copy constructor). This means struct
        /// processing and alignment should have already occured. This also
        /// means the function will be queued for being constructed into
        /// WASM binary like all other functions in a later pass.
        /// </summary>
        /// <param name="autocreate">If the function doesn't exist, auto
        /// create a default copy constructor and register it with the struct.
        /// </param>
        /// <returns>The found, or created, copy constructor for the struct.</returns>
        public override SynFuncDecl GetCopyConstructor(bool autocreate, SynNestingBuilder scb)
        {
            List <SynFuncDecl> lstFns;

            if (this.functions.TryGetValue(this.typeName, out lstFns) == false)
            {
                if (autocreate == false)
                {
                    return(null);
                }

                // If we're autocreating, prepare a list for it to be registered in.
                lstFns = new List <SynFuncDecl>();
                this.functions.Add(this.typeName, lstFns);
            }
            else
            {
                foreach (SynFuncDecl fns in lstFns)
                {
                    if (fns.returnType != null)
                    {
                        continue;
                    }

                    if (fns.parameterSet.Count != 2)
                    {
                        continue;
                    }

                    if (
                        fns.parameterSet.Get(0).type != this ||
                        fns.parameterSet.Get(1).type != this)
                    {
                        continue;
                    }

                    return(fns);
                }

                if (autocreate == false)
                {
                    return(null);
                }
            }

            SynFuncDecl sfdCC = new SynFuncDecl(this);
            //
            SynVarValue svvDst = new SynVarValue();

            svvDst.varLoc   = SynVarValue.VarLocation.ThisRef;
            svvDst.dataType = SynVarValue.VarValueDataType.Pointer;
            //
            SynVarValue svvSrc = new SynVarValue();

            svvSrc.varLoc   = SynVarValue.VarLocation.Parameter;
            svvSrc.dataType = SynVarValue.VarValueDataType.Reference;

            sfdCC.parameterSet.AddParameter(svvDst);
            sfdCC.parameterSet.AddParameter(svvSrc);

            // TODO: Do explicit alignment here?

            // Add this ahead of time
            lstFns.Add(sfdCC);

            // Go through each variable in order and copy them by producing the proper AST
            for (int i = 0; i < this.varDefs.Count; ++i)
            {
                SynVarValue svv = this.varDefs[i];    // The member to copy

                if (svv.type.intrinsic == true)
                {
                    AST astSrcDeref     = new AST(new Token(-1, svv.varName, TokenType.tyWord), scb, ASTOp.DerefName, null, svv.type, false, AST.DataManifest.Procedural, 0);
                    AST astSrcGetMember = new AST(new Token(), scb, ASTOp.GetMemberVar, svvSrc, this, false, AST.DataManifest.Procedural, 0, astSrcDeref);

                    AST astDstDeref     = new AST(new Token(-1, svv.varName, TokenType.tyWord), scb, ASTOp.DerefName, null, svv.type, false, AST.DataManifest.Procedural, 0);
                    AST astDstGetMember = new AST(new Token(), scb, ASTOp.GetMemberVar, svvSrc, this, false, AST.DataManifest.Procedural, 0, astSrcDeref);

                    AST astSetVar = new AST(new Token(), scb, ASTOp.SetValue, null, null, false, AST.DataManifest.NoData, 0, astSrcDeref, astSrcGetMember);
                    sfdCC.ast.branches.Add(astSetVar);
                }
                else
                {
                    // Else, it's a sub-struct, and we use GetCopyConstructor() recursively
                    // to copy it.
                    throw new SynthExceptionCompile("Class copy constructors are not supported.");
                }
            }

            return(sfdCC);
        }
Beispiel #12
0
        public void ParseContext(List <Token> tokens)
        {
            SynLog.LogHeader("Starting Parse Content");
            SynLog.Log("\tTokens:");
            SynLog.Log(tokens);

            //      Get param globals first
            //
            //////////////////////////////////////////////////
            while (tokens.Count > 0)
            {
                SynVarValue parsedParam = SynVarValue.ParseExposedParam(tokens);
                if (parsedParam == null)
                {
                    break;
                }

                this.AddVariable(parsedParam);
            }

            //      Parse Sections
            //
            //////////////////////////////////////////////////
            int idx = 0;

            while (tokens.Count > 0)
            {
                // Get rid of stray parenthesis
                if (tokens[idx].Matches(TokenType.tySymbol, ";") == true)
                {
                    tokens.RemoveAt(0);
                    continue;
                }

                // Struct parsing
                if (tokens[0].Matches(TokenType.tyWord, "struct") == true)
                {
                    SynStruct sst = SynStruct.Parse(this, tokens);
                    if (sst != null)
                    {
                        this.AddType(sst);
                        continue;
                    }
                }

                // Function parsing
                if (tokens[0].Matches(TokenType.tyWord, "entry") == true)
                {
                    SynFuncDecl sfd = SynFuncDecl.Parse(this, tokens, "", true, SynFuncDecl.ParseType.Entry);
                    sfd.callType = SynFuncDecl.CallType.Entry;

                    if (sfd != null)
                    {
                        this.AddFunction(sfd);
                        continue;
                    }
                    else
                    {
                        throw new System.Exception("entry keyword not part of valid function.");
                    }
                }

                SynFuncDecl synthFn =
                    SynFuncDecl.Parse(
                        this, tokens,
                        "",
                        true,
                        SynFuncDecl.ParseType.RootContext);

                if (synthFn != null)
                {
                    this.AddFunction(synthFn);
                    continue;
                }

                SynVarValue synthVar = SynVarValue.ParseBodyVar(tokens, SynVarValue.OuterScope.Global);
                if (synthVar != null)
                {
                    this.AddVariable(synthVar);
                    continue;
                }

                throw new System.Exception("Unknown token while parsing root context.");
            }

            //      Verify Structs
            //
            //////////////////////////////////////////////////
            SynLog.LogHeader("Verifying types");

            while (true)
            {
                TypeConsolidate tc = this.ResolveStaticTypeAlignments();
                if (tc == TypeConsolidate.UndeterminedNoChange)
                {
                    throw new System.Exception("Could not resolve all types");
                }

                if (tc == TypeConsolidate.AllDetermined)
                {
                    break;
                }
            }

            SynLog.Log("Finished verifying struct successfully.");

            //      Gathering globals
            //
            //////////////////////////////////////////////////
            SynLog.LogHeader("Gathering globals");

            List <SynVarValue> globals = new List <SynVarValue>();

            foreach (SynScope s in this.EnumerateScopes())
            {
                s.RegisterGlobals(globals);
            }

            this.totalGlobalBytes = 0;
            foreach (SynVarValue svv in globals)
            {
                svv.alignmentOffset = this.totalGlobalBytes;

                int byteSz = svv.type.GetByteSize();
                if (byteSz <= 0)
                {
                    throw new SynthExceptionImpossible("Data type for global variable is zero in size.");
                }

                SynLog.Log($"Added {svv.varName} to globals at offset {svv.alignmentOffset}");

                this.totalGlobalBytes += byteSz;
            }

            SynLog.Log($"Total global variable space is {this.totalGlobalBytes}.");

            //      Verify Functions
            //
            //////////////////////////////////////////////////
            SynLog.LogHeader("Verifying After function and variable collection pass.");
            this.Validate_AfterTypeAlignment(0);

            SynLog.Log("Finished verifying functions successfully.");
        }