public AST(Token t, SynNestingBuilder builder, ASTOp ast, SynObj so, SynType sevty, bool hasAddress, DataManifest manifest, int ptrDepth, params AST [] branches) { this.builder = builder; this.synthObj = so; this.evaluatingType = sevty; this.token = t; this.astType = ast; this.hasAddress = hasAddress; this.manifest = manifest; this.ptrDepth = ptrDepth; this.branches = new List <AST>(); // Should we always allocate this? if (branches != null && branches.Length > 0) { this.branches.AddRange(branches); } }
public virtual SynFuncDecl GetCopyConstructor(bool autocreate, SynNestingBuilder scb) => null;
// 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); }
/// <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); }