public override void Validate_AfterTypeAlignment(int logIndent) { SynLog.Log(""); SynLog.LogIndent(logIndent, $"Begin Struct.Validate_AfterTypeAlignment : {this.typeName}"); base.Validate_AfterTypeAlignment(logIndent + 1); SynLog.LogIndent(logIndent, $"End Struct.Validate_AfterTypeAlignment"); }
public override void Validate_AfterTypeAlignment(int logIndent) { SynLog.LogIndent(logIndent, $"Starting SynthRegion.Validate_AfterTypeAlignment : {this.name}"); base.Validate_AfterTypeAlignment(logIndent + 1); SynLog.LogIndent(logIndent, "Ending SynthRegion.Validate_AfterTypeAlignment"); }
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; } } }
public void ParseFile(string filepath) { SynLog.LogHeader("Parsing file " + filepath); using (var scope = new SynLog.LogScope()) { string fileContents = System.IO.File.ReadAllText(filepath); this.ParseString(fileContents); } }
/// <summary> /// Do validation and further processing after types, and function, have been validated /// and type have been aligned. /// </summary> public virtual void Validate_AfterTypeAlignment(int logIndent) { SynLog.LogIndent(logIndent, "Started base.Validate_AfterTypeAlignment"); foreach (SynScope ss in this.EnumerateScopes()) { ss.Validate_AfterTypeAlignment(logIndent + 1); } SynLog.LogIndent(logIndent, "Ended base.Validate_AfterTypeAlignment"); }
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); }
public override void Validate_AfterTypeAlignment(int logIndent) { SynLog.LogIndent(logIndent, $"Started Context.Validate_AfterTypeAlignment()"); if (varDefs.Count != 0) { throw new SynthExceptionImpossible("Root context found with local members. Only global members should be possible."); } foreach (SynFuncDecl scopeFn in this.EnumerateScopedFunctions()) { if (scopeFn.isStatic == false) { throw new SynthExceptionImpossible("Root context found with local methods. Only static functions should be possible."); } } base.Validate_AfterTypeAlignment(logIndent + 1); SynLog.LogIndent(logIndent, $"Ended Context.Validate_AfterTypeAlignment()"); }
public void RealignFunctions() { SynLog.Log($"Realigning function indices."); List <FunctionInfo> origFnInfos = this.functionInfos; this.functionInfos = new List <FunctionInfo>(); uint idx = 0; foreach (FunctionInfo fi in origFnInfos) { if (fi.imported != true) { continue; } fi.functionIndex = idx; ++idx; this.functionInfos.Add(fi); } foreach (FunctionInfo fi in origFnInfos) { if (fi.imported == true) { continue; } fi.functionIndex = idx; ++idx; this.functionInfos.Add(fi); } }
// 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); }
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()); }
public SynthExceptionSyntax() : base() { SynLog.Log("SYNTAXERROR!"); }
public SynthExceptionSyntax(Token t, string why) : base($"Syntax Error line {t.line}: " + why) { SynLog.Log($"Syntax Error line {t.line}: " + why); }
public SynthExceptionSyntax(int line, string why) : base(why) { SynLog.Log($"Syntax Error line {line}: " + why); }
public SynthExceptionCompile(string why) : base(why) { SynLog.Log("COMPILE!: " + why); }
public SynthExceptionCompile() : base() { SynLog.Log("COMPILE ERROR!"); }
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."); }